Click here to Skip to main content
Click here to Skip to main content

Enhanced Transparent Flash Control in C++

By , 28 Apr 2011
 
EnhancedFlashControl screen shot

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 JavaScript, or container projector)
    // passing two parameters, and assigning that function's result 
    // to the variable "counter"
    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. It 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 

CustomBuild.gif

Acknowledgements

Special thanks to the authors of:

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 cannot 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!

History

  • 8th April, 2011: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Fred van Lieshout
Software Developer (Senior) Sioux Automation Technology, Utrecht
Netherlands Netherlands
Member
Fred is an experienced software engineer with in-depth knowledge of software design, coding and testing. He is interested in the analysis and design phases in particular, but still enjoys ‘getting his hands dirty’ with software programming.
 
LinkedIn: profile

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 5memberflyhigh26 Oct '12 - 3:30 
good job. I'm looking for it for a long time.
GeneralRe: My vote of 5memberFred van Lieshout26 Oct '12 - 7:58 
Thank you. Glad that this has helped you!
QuestionGood jobmemberwshcdr16 Oct '12 - 19:59 
Well done!
It is better of me!

AnswerRe: Good jobmemberFred van Lieshout17 Oct '12 - 10:21 
Thanks! Always good to receive feedback...
QuestionDoesn't compilememberMichael Haephrati29 Sep '12 - 6:02 
I get these error messages (I use VS2010)
1>

AnswerRe: Doesn't compilememberFred van Lieshout1 Oct '12 - 5:25 
Hi Michael,
 
I'm afraid that a little more information than just "1>" is required in order to get an answer to your problem....
 
Something must have gone wrong during copy/paste.
 
Cheers,
Fred
QuestionIs it possible to wrap it all up into one executable?memberalikim2 Dec '11 - 1:17 
Hi,
 
I'm very new to C++, I need to create one executable file that would run (wrap around) Flash Player 11 that in turn runs an SWF inside it.
 
All of it in a transparent window with the same API as in your article.
 
It should run under Win7 and WinXP on any PC without any ActiveX and Flash Player or any other frameworks/components installed.
 
Is it possible to modify your code so it will produce that one file?
 
Thank you!
AnswerRe: Is it possible to wrap it all up into one executable?memberFred van Lieshout4 Dec '11 - 1:42 
Hi Alikim,
 
Good question! Unfortunately I doubt that this possible. Wrapping another executable is one thing, but, as far as I know, the player does require ActiveX registration. Perhaps you should try other fora to get this answered.
 
Good luck!
GeneralRe: Is it possible to wrap it all up into one executable? [modified]memberalikim4 Dec '11 - 2:15 
I see, I know programs like SWF Studio or mProjector do exactly that, and never ask to register anything, so I thought it's possible.
 
I don't know what other forum to use because I'm not even sure what question to ask, but thanks anyway.

modified 4 Dec '11 - 12:02.

Question64 bit flashmemberMember 830542810 Oct '11 - 5:54 
Fred,
 
As I'm sure you are aware, Adobe has released a 64 bit version of their Flash player.
I tried compiling your code in VS2008 in 64 bit mode and it crashes in flash_11_0_1.ocx when the m_bTransparent flag is true. The crash happens when the WMode is set to transparent or opaque.
Any thoughts?

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130523.1 | Last Updated 28 Apr 2011
Article Copyright 2011 by Fred van Lieshout
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid