Enhanced Transparent Flash Control in C++
Introduction
This article is based on the excellent article written by Makarov Igor. It extends the functionality with support for calls and callbacks between C++ and Flash ActionScript.
Background
Because I was looking for some (C++) code to play a Shock Wave Flash (.swf) file with ActionScript, I found the above referenced article. However, it did not have support for calls and callbacks. There's plenty of documentation on the Flash ExternalInterface, but I found it hard to find a working example. So I added it and thought it may be useful to others as well.
Using the code
Since Flash uses XML for marshalling parameters back and forth on the ExternalInterface, I decided to use the TinyXML library. It is included in the sample code.
Part 1. Flash ActionScript
Let's start with the ActionScript part. In the file "HelloWorld.as" there is a line that tells the ExternalInterface of Flash to register a callback:
// Register a callback on the Flash External Interface that can
// be called from C++ (or any other container, e.g. javascript)
ExternalInterface.addCallback("setButtonText", onSetButtonText);
The above code registers the ActionScript function with the name onSetButtonText
, which can be called by the name setButtonText
from e.g. javascript (if the container would be a web browser) or C++ (in this example).
The function onSetButtonText
simply sets the text of the button, purely for demonstration purposes:
public function onSetButtonText(arg:String):String {
button.setLabel(arg);
return "OK";
}
Each time the user clicks the button in the Flash ActionScript, the mouseDownHandler
is called. For animation it changes the x and y coordinates and it calls count
to get new text for the button:
private function mouseDownHandler(event:MouseEvent):void {
button.x += 1;
button.y += 1;
button.setLabel(count());
}
Below is an example of how to call the Flash ExternalInterface from ActionScript. It calls the addNumbers
function. Handling this call in C++ code is described in the next paragraphs.
// Demonstration on how to use the Flash ExternalInterface
// This example calls the function 'addNumbers' in the C++ container app
public function count():String {
// calls the external function "addNumbers" (in java script, or container projector)
// passing two parameters, and assigning that function's result to the variable "result"
ExternalInterface.marshallExceptions = true;
try {
counter = ExternalInterface.call("addNumbers", counter, 1);
return String(counter);
}
catch(e:Error) {
return e.toString();
}
return String("Error");
}
Part 2. Event handling in the C++ code
As mentioned before, the code is re-used. The function CFlashWnd::Invoke
has been enhanced so that it understands the events dispatched from Flash. If all parameters are OK, it calls the FlashCall
method.
HRESULT STDMETHODCALLTYPE CFlashWnd::Invoke(...)
{
if (wFlags == DISPATCH_METHOD)
{
switch (dispIdMember)
{
case 0xc5: // FlashCall (from ActionScript)
if (pDispParams->cArgs != 1 || pDispParams->rgvarg[0].vt != VT_BSTR)
return E_INVALIDARG;
return this->FlashCall(pDispParams->rgvarg[0].bstrVal);
The CFlashWnd::FlashCall
then does the dirty work, i.e. unmarshalling the XML. Parsing the request is done by the call to the Tiny XML library function doc.Parse
. Flash passes the call details in an XML <invoke> element. It is looked up by hDoc.FirstChildElement("invoke")
. The name of the called function is specified in attribute "name" of the <invoke> element. It is looked up by a call to QueryStringAttribute
. If all information is OK, the whole element tree is passed on to the addNumbers
method.
// Handle a call from Flash ActionScript (in .swf file)
HRESULT STDMETHODCALLTYPE CFlashWnd::FlashCall(_bstr_t request)
{
HRESULT hr = S_FALSE;
if (m_lpControl != NULL)
{
TiXmlDocument doc;
const char *c_str = _com_util::ConvertBSTRToString(request);
// Parse the XML string to into an XML doc
doc.Parse(c_str);
delete[] c_str;
TiXmlHandle hDoc(&doc);
// Look for the invoke element
TiXmlElement *pInvokeElement = hDoc.FirstChildElement("invoke").Element();
if (pInvokeElement != NULL)
{
std::string functionName;
int result = pInvokeElement->QueryStringAttribute("name", &functionName);
if (result == 0)
{
if (functionName == "addNumbers")
{
// Finally, handle the request
hr = addNumbers(pInvokeElement);
}
}
}
}
return hr;
}
The above code shows a very simple way to handle function call requests from Flash ActionScript. Feel free to improve this if you wish to handle more calls. After all, this is just demonstrating the basics of the mechanism.
Part 3. Returning the result from C++ to ActionScript
So CFlashWnd::FlashCall
is now capable of decoding the called function name. Now let's take a look at how to decode the function arguments and pass the function result (return value) back to the Flash object (ExternalInterface) as a number:
HRESULT CFlashWnd::addNumbers(TiXmlElement *pInvokeElement)
{
HRESULT hr = E_INVALIDARG; // Default result if something is wrong
TiXmlElement *pArgumentElement = pInvokeElement->FirstChildElement("arguments");
if (pArgumentElement != NULL)
{
TiXmlElement *pArgumentNumber = pArgumentElement->FirstChildElement("number");
if (pArgumentNumber != NULL)
{
int number1 = atoi(pArgumentNumber->GetText());
pArgumentNumber = pArgumentNumber->NextSiblingElement("number");
if (pArgumentNumber != NULL)
{
int number2 = atoi(pArgumentNumber->GetText());
WCHAR result[80];
_snwprintf_s(result, 80, 80, L"<number>%d</number>", number1 + number2);
// Set the return value in the Flash object (ExternalInterface)
hr = m_lpControl->SetReturnValue(result);
}
}
}
return hr;
}
The above code shows how to pass the result back to Flash by calling SetReturnValue
on the ActiveX interface. Its also also shows how to use the function from the Tiny XML library to get the required argument values.
Part 4. Calling ActionScript from C++
A simple example of how to call ActionScript from C++ is shown below. Note that ExternalInterface.addCallback
must have been called in the ActionScript, see part 1, or otherwise things will fail!
BSTR _result = m_lpControl->CallFunction(L"<invoke name=\"setButtonText\" returntype=\"xml\"><arguments><string>Click me!</string></arguments></invoke>");
Building the Flash ActionScript
To compile the .as file into an .swf file that can be played by the Flash player, I used the free mxmlc compiler from Adobe. You can download it from their site.
To build it as part of the Visual Studio project, add a custom build rule:
"F:\Program Files\Adobe\Flex_SDK_4.0\bin\mxmlc.exe" --show-actionscript-warnings=true --strict=true -static-link-runtime-shared-libraries -output $(OutDir)\$(InputName).swf $(InputName).as
Acknowledgements
Special thanks to the authors of:
- Transparent Flash Control in Plain C++
- Tiny XML
- An unknown source for providing the starting point for the ActionScript.
Without them it would have been a lot harder to write the code!
Legal stuff
Unfortunately we live in a world where these kind of messages are necessary...
This article and source code have been provided to you for use as you see fit, without any warranty! This article and source code only demonstrate the basic principles and should not be used in situations that can do harm to people, animals or cause risks of any kind. Please use it at your own risk, not mine. I can not be held responsible, you have been warned.
Sorry for that, I hope it doesn't sound too offensive. Because, after all, coding should be fun!
Post Comment
acPdJa This is a list of words, not an essay. you are incompetent
FEf3eR This website truly has all the info I needed about this subject and didn at know who to ask.
yY1yps Muchos Gracias for your blog.Really looking forward to read more. Great.
Wow that was odd. I just wrote an really long comment but after I clicked submit my comment didn at show up. Grrrr well I am not writing all that over again. Anyhow, just wanted to say superb blog!
w3cMca Superb Post.thanks for share..much more wait..
L0K5ve Perfectly composed content material , thankyou for entropy.
6MABYT
9gFN67 wow, awesome article.Really looking forward to read more.
emiAC0 A big thank you for your article.Really thank you! Really Great.
G1a3Ba Im obliged for the blog post.Really thank you! Will read on
DYZ3cm Awesome blog article.Thanks Again. Really Cool.
kdgUb1 Hey, thanks for the blog.Really thank you! Will read on...
zVuYgX Awesome blog post.Really thank you! Fantastic.
ahLeZk Really enjoyed this article post.Much thanks again. Awesome.
yH5HqK Thanks-a-mundo for the blog post. Much obliged.