Email Updates RSS Subscribe
Line

This blog is created and maintained by the technical team at Hook in an effort to preserve and share the insights and experience gained during the research and testing phases of our development process. Often, much of this information is lost or hidden once a project is completed. These articles aim to revisit, expand and/or review the concepts that seem worth exploring further. The site also serves as a platform for releasing tools developed internally to help streamline ad development.

Launch
Line

Hook is a digital production company that develops interactive content for industry leading agencies and their brands. For more information visit www.byhook.com.

Line

Alchemy Series Part 3: Ubiquitous Hello World

Line
Posted on March 9th, 2011 by Jake
Line

Welcome to Part 3, where we finally get to write some C code! Yay! This part is designed to get you comfortable with building up a C file from scratch for use within flash, and get used to the compiling and access process. This example swc has two functions. sayHi() and echoMe(). We are going to break these down into as much detail as we can, to get prepared for the next part in the series which talks about real data manipulation. That post however is already getting pretty long, so we split out this section as a primer for Part 4.

Please download the source files for this example here.

Also please make sure that you have the alchemy environment setup and running from Part 2.

Now go ahead and launch Cygwin.bat and get your Cygwin shell up and running.

Quick Cygwin Intro
First lets go over a few Cygwin Bash Shell commands:
At any point you can open the manual (man pages) which has more info on each of these commands. To access those simply type:

man command

and press enter.

Replace “command” with the command you are interested in. An example of this would be:
man ls

That will give you something that looks like this:

Use the arrow keys to move up and down, and “q” to quit.

Useful Cygwin Commands:
ls:
This will list the files in the current directory. Some useful options are -a -l -h. A is for
“All”, l is for “Long”, and h is for “Human Readable”.
You can combine them like this:
ls -alh

cd:
Change directory. There are no drive letters in Cygwin. So “cd” gets you everywhere.
cd /cygdrive/e/alchemyStuff
That will put you in the “alchemyStuff” directory of the “c” drive.

pwd:
Print Working Directory. Just tells you what directory you are in.
When you see a “~” that means your home directory.

rm:
Remove – it deletes stuff, so rm dumbFile.c will delete dumbFile.c.

ln:
Create a link. Kind of a shortcut to a folder. I generally use the “-s” option and make a
symbolic link to my current project (saves a lot of cd’ing):
ln -s /cygdrive/e/AlchemyHelloWorld
This will put the link/shortcut into whatever directory you are currently in.
So now from my home directory (cd ~) I can quickly get to my project:
cd AlchemyHelloWorld

dos2unix:
If you create a file in windows, it uses different line endings, newline + carriage return
Cygwin just used new line. So if you run:
dos2unix myWindowsFile.sh
It will convert the linendings and other little things to the proper format.

./:
The dot+slash is super useful. Your current working directory is probably not in the
global path. So in order to run anything you will need to put a ./ in front of it. As you will
see later in this post, to compile our stuff, we will use:
./compileHello.sh
That runs the bash script “compileHello.sh” from the current directory.

Now with that out of the way we can get to the good stuff. Lets take a quick look at the files in the example:
alchemy folder:
- compileHello.sh
this is a script that does our compiling.

- hello.c
this is the C code for our hello world alchemy library

- hello.swc
this is the compiled swc that we will access from flash.

bin folder:
This is the standard FlashDevelop AS3 Project bin folder. Just contains the index.html
file and the swf of our example. Nothing special here

src folder:
- Main.as
this is our document class that is the entry point for the example.

This example doesn’t have any on stage visual output so its not embedded in the page like the examples in the other posts. Which means you will have to download the example and run it through FlashDevelop or some other IDE to catch the trace output. Which brings us to….

Setting up the example
If you are using FlashDevelop, then all you have to do is double click on the project file. Then navigate to the alchemy folder and right click on the “hello.swc” file, and select “Add To Library”. Then press F5. In the output pane you should see:

(fcsh)Build succeeded
Done(0)
[Starting debug session with FDB]
Generating Hi Message in Alchemy
Response From Alchemy: Hi From Alchemy!
Echo: Echo This!

If you are using the Flash CS5 IDE, you will need to create a new .fla file in the “src” folder, and use “Main” as the document class. Then go to File->Publish Settings->Flash->ActionScript3 Settings->Library Path and add “../alchemy” as a library path.
Now do a “ctrl-enter” and you shoudl get the following output:

Generating Hi Message in Alchemy
Response From Alchemy: Hi From Alchemy!
Echo: Echo This!

Compiling
Cool, so now that you know what the end result is, lets compile the hello.c file from scratch, shall we?

Pop into the Cygwin shell, and “cd” your way to where ever you have the source files extracted to.

First we have to turn alchemy “on”, so type:
alc-on

and press enter. Now when you run gcc it will run through Alchemy.

To do that go into the /alchemy folder and type:
./compileHello.sh

This is a bash script that I made so I don’t have to type so much. The contents of the script look like this:

#!/bin/bash
gcc -Wall hello.c -swc -O3 -o hello.swc

The first line tells Cygwin that it should use “bash” to interpret the script. The next line is the actual gcc command. Now remember if you make a bash script in windows (like in notepad or whatever), and access it through Cygwin, you will need to run “dos2unix compileHello.c” to convert the end lines.

gcc obviously executes the gcc compiler and then we pass a few options to it.
First -Wall, this says, turn all of the (W)arnings on. Next is the .c file that we want to compile, and in this case its hello.c. Next -swc says create a swc. -O3 sets the optimiztion to level 3 (compiler level optimizations will do things like inline your functions and various other compiler voodoo to make your stuff execute faster). Lastly -o says output to hello.swc.

If all goes well you may get a warning about POSIX file paths, (which can be ignored, see previous post) and a warning about ‘main’ arguments being dropped. This can also safely be ignored. You should then get a bunch of other stuff that prints out that looks like:

So after all of that preliminary stuff, we can finally get on to the code. Pop open the alchemy/hello.c file, and lets go through it.

Finally Some Code
When starting a new C file that needs flash access you will need to include the “AS3.h” header file.

#include "AS3.h"

That will get you access to the various AS3 Value types, and the functions that allow you to convert data to and from ActionScript types.

Now jump down to the main() function at the very bottom. This is where the initial setup happens that exposes your carefully crafted C functions to flash. First up is the creation of a virtual function (basically an ActionScript function object that will reference a C function) or a “Thunk” as its technically called.

//Create the thunk (a virtual function that can be exposed to flash)
//this assigns a reference to a C function to an AS3 Function
//definition that can be passed to AS3_Object()
AS3_Val sayHiMethod = AS3_Function(NULL, sayHi);
AS3_Val echoMeMethod = AS3_Function(NULL, echoMe);

The first thing beyond the comments is “AS3_Val” this a data type that comes with “AS3.h”. Basically its a place to store objects that are going to ActionScript or coming from ActionScript. In this case, its going to put assigned to an object that is going to be visible to ActionScript.

//Bundle up the thunks into an AS3 Object.  This object is what flash sees
//after you call init() on the loaded Alchemy loader.
AS3_Val flashObj = AS3_Object("alchemySayHi:AS3ValType, alchemyEchoMe:AS3ValType", sayHiMethod, echoMeMethod);

This is where we actually expose things to ActionScript. The “flashObj” object will be available as a means of communication between our flash bits and our alchemy bits. AS3_Object is a function that creates an as3 object with the properties passed in as its arguments. The first argument is a comma separated list of propertyName:propertyType value pairs. The second argument is the values of those properties. In the next part of the series we will be taking a deeper look into AS3_Object as well as the other data management abilities of alchemy. So for now, just know that this is where you give flash access to your C/Alchemy functions. So in this case, the object will have a property on it called “alchemySayHi” and it will be of type AS3ValType. This property will contain a reference to our thunk “sayHiMethod” from a few lines before. That thunk references the C sayHi() function. So from flash we can call lib.alchemySayHi() and it will execute the C sayHi() function. Just to be a little clearer, “lib” in this case is the returned “flashObj” that we created. The same goes for the “alchemyEchoMe” property, that will reference the “echoMeMethod”, which in turn executes the echoMe() C function. Got all that? :)

As you are I’m sure well aware, Flash/ActionScript is a “Managed” system. Meaning that the virtual machine manages all of the memory allocation and freeing. This is good and bad, but in either case a discussion for another time. C on the other hand is not a managed system. Meaning that if we create stuff that takes up memory, we need to free that same stuff, so we don’t leave memory stranded out there that can no longer be accessed. The rule of thumb is, if we create it, we release it. There is one exception however. If you are returning an object that you created it will be released automatically. The last bit to keep in mind in terms of memory management is that when compiled down through Alchemy, the C code is now Adobe Virtual Machine byte code. Which means it runs with in the VM. Which ultimately means the memory is managed. However, the Garbage Collector won’t know to free up the memory used in the C code if you don’t explicitly free it. So for all intents and purposes, you can just pretend that the C code is still an unmanaged memory system. Just know its lie :)

So all of that was to simply justify these lines:

//We created a new AS3_Val, so we have to release it now that we are done with it
AS3_Release(sayHiMethod);
AS3_Release(echoMeMethod);

Lets take a quick break from C for the moment, and see how we can use the stuff in the main() function. If you pop open Main.as in the /src folder, and meander down to the init() function you will see this:

//Setup the alchemy library
_loader = new CLibInit();
_lib = _loader.init();

When you compile your C code through Alchemy, it builds you a swc with a package path that looks like this:

import cmodule.hello.CLibInit;

Its cmodule.your_swc_name. In there is the CLibInit class. This is the Alchemy loader. You new that up, and then call init() on the new CLibInit object. This is what runs your main() function from the C code. This retuns that “flashObj” object that we attached the two function references to. That means we are free to do some crazy stuff like this:

//Now that we are all set up, we can call the exposed method
var response:String;
response = _lib.alchemySayHi();
trace("Response From Alchemy: " + response);

Holy moly thats some ridiculous stuff right there. Basically its doing what it says. Its finding the “alchemySayHi” property from the Alchemy object, and executing that as a function, which it is, because we stored an AS3_Function(NULL, sayHi) in that property.

Ok, so we didn’t spend that long in ActionScript, but I figure you know how most of that works already :) Back to C!

Lets take a look at the sayHi() function in hello.c

AS3_Val sayHi(void *data, AS3_Val args)

That is the start of the function definition for sayHi(). Now, I’m not going to lie, I don’t know how to use the first parameter, void *data. The docs state this:
“Create a synchronous function callback object, binding the function pointer with the data passed in. data can be used to hold state for the function”
So for now, I’m going to skip it until I understand it enough to properly inform you. The second parameter however, I have a grasp on: AS3_Val args
When you call a thunk from ActionScript it passes the parameters to this argument as an AS3 Array. You can then pull apart that Array and use those passed in values within your function. There is an example of that in the echoMe() function. We will get to that in a bit.

Next up in the sayHi() function is:

AS3_Val traceOut;
traceOut = AS3_String("Generating Hi Message in Alchemy");

First we make a variable of type AS3_val and call it “traceOut”. This is going to be passed to an AS3_Trace() call. If you check out the docs for AS3_Trace() you will see that it takes an AS3_Val val as its parameter. So we need to make one of those, and in this case we called it “traceOut”. Now that we have our AS3_Val we are going to want to store a string in it. In C there is no real concept of strings. They are essentially pointers to a list of chars. We will go more into that in a bit. For our current case however, we are going to make an AS3_String and store that into traceOut. Which will then be traced out. Super exciting.. I know…

traceOut = AS3_String("Generating Hi Message in Alchemy");
AS3_Trace(traceOut);

It might be a good time to point out that AS3_String() is not a cast, it is a real C function defined in Alchemy. This creates a new object that is of type AS3_String. So just keep in mind that the only real ActionScript data type here is the AS3_Val type. There is no AS3_String type, its a factory function.

But alas, I said the word create again. Which can only mean one thing:

//We created it, we release it
AS3_Release(traceOut);

Finally for a little added pizazz (yes I said pizazz), we are going to return something back to ActionScript. Part 5 of our series will talk at length about communicating between Flash and the Alchemy code, but I figured I could slip this in now :)

//Retun a string (an as3 string mind you) to flash
//When something is returned, it is automatically "released"
return AS3_String("Hi From Alchemy!");

So in Main.as this is where “High From Alchemy!” is returned:

response = _lib.alchemySayHi();
trace("Response From Alchemy: " + response);

This is what give us the output you see in your output window :)

Lastly we are going to talk about the echoMe() function in hello.c. I’m going to skim this one a bit, as it dips into the pool of the Part 4 post on data manipulation, but I figured I better give you something so you come back next time :)

The function:

/*****************************************************************************
* echoMe:
*		This function will take a string from Flash, and trace it out.
* 
* arguments:
*		(AS3_String) a string of text to echo out.
*
* returns:
* 		(AS3_Val) NULL
******************************************************************************/
AS3_Val echoMe(void *data, AS3_Val args)
{//echoMe
 
	//Declare a variable to hold our input (which will be an as3 string)
	char* inputString;
 
	//Parse "args" array from flash
	AS3_ArrayValue(args, "StrType", &inputString);
 
	//Do the echo to stderr
	fprintf(stderr, "Echo: %s", inputString);
 
	//We created it, we release it
	free(inputString);
 
	//Return nothing.
	//Compiler is expecting an AS3_Val to be returned.
	//We have to use AS3_Val so we can create the thunk in main()
	//Therefore we have to return something, which in this case is nothing :)
	//Ok, well its not nothing, its Null, and more than that its an AS3 null,
	//not a C null.
	return AS3_Null();
 
}//echoMe

So the function definition is exactly the same as the sayHi() function. But then everything gets all different and stuff, and we sort of exit ActionScript land, and splash around a bit in puddles of C code.
The first line declares a varible called inputString. This is of type char* which is a C type. Basically its a point to a memory address that will contain a list of characters. Sounds familiar doesn’t it?
Next we use the AS3_ArrayValue() function to pull apart the “args” parameter. The first parameter in the AS3_ArrayValue() call is the source array from flash. In this case its “args”. The next parameter is a string of comma separated Class/Type names. This describes what the type of each element in the array is, so order is paramount. The last parameter is where the value from the array will be stored. In this case its going to be stored at the memory address specified by inputString. (for more info, look up C pointers and dereferencing). If you check out the docs for AS3_Array you will see a list of types and what they map to in C. In this case “StrType” maps to char*. Go figure :)

Cool, so now, what do we do. Well, list print out whatever was passed into the echoMe() call. This time we are going to use a C function to do it, fprintf(). That is another one you are going to have to look up. C programming is a bit beyond the scope of this post, but I will explain whats going on a bit here.

fprintf(stderr, "Echo: %s", inputString);

Stderr stands for Standard Error. We are telling fprintf to print our stuff out to the standard error pipe. We do this so that FlashDevelop and the Flash IDE catch it and display it in the output window. The next parameter is a string. In this string is a %s which tells fprintf that you want to replace that %s with a char* value. Hence the third parameter, intputString, which as you know is a char* value. So when this is executed, it will display
“Echo: Echo This!”
or whatever you pass in to it.

Now, since we created a char*, we need to free it, which is what the free() call does. Go figure.
Lastly, since we promised the compiler that this function was going to return a AS3_Val, we need to do that. However, since we don’t have anything useful to return we are just going to return an AS3_Null(). Now again, remember, AS3_Null() is a function that creates an object, which flash will read as Null, so again, its not a cast.

Whew, for so few lines of code, that took some serious explaining. Hopefull this will help you understand how to get started with this stuff. In the next part we are going to try to do something useful :)

As always, if you want updates for when new posts come out, Like us on facebook at the Hook page:

And/Or follow me on Twitter:
Follow JakeCallery on Twitter

Tune in next time, on the same bat channel. (I would have said same bat time too, but I can’t promise that :) )

Line
6 Responses to “Alchemy Series Part 3: Ubiquitous Hello World”
  1. ym says:

    Hi,

    i’ve start to use alchemy by your Alchemy Series, and realized that first call from swc takes more time then second and later calls. Do you have any idea why it could happen? (sample code is below)

    Thanks Regards.

    var loader:CLibInit = new CLibInit;
    var lib:Object = loader.init();

    timer = getTimer();
    trace(lib.echo_(“foo”));
    trace(“time passed : ” + (getTimer() – timer)); //time passed : 44

    timer = getTimer();
    trace(lib.echo_(“foo”));
    trace(“time passed : ” + (getTimer() – timer)); //time passed : 9

    • Jake says:

      To be honest, I’m not sure why that is. Have you tried waiting a bit after loader.init() is called before running the traces? I’m curious to see if that maybe is some sort of async call, and while its loading, the commands are queued or something… Cool find though!

      • ym says:

        Its just for first call, prob first reading from memory takes time. Seems better to use an echo method right after initalizing.

  2. Fintan says:

    Hi Jake,

    I haven’t touched alchemy yet and was wondering if the alchemy generated swc file can call functions that are contained in dll files on the user’s machine. My guess is that this isn’t possible -everything needs to be self-contained within the swc and availing of a dll is outside of the security sandbox of the swf file that uses the swc.

    are my assumptions correct or is alchemy even more versatile than I realise?

    thanks,

    Fintan

    • Jake says:

      Though that would be awesome, it unfortunately doesn’t work that way… the C files are compiled down into AVM bytecode, and the dlls wouldn’t be. So your assumptions are correct, however if you can get the C source for the .dll files, you could in theory recompile it to work in your swf :)


Leave a Reply

*

Line
Line
Pony