C++与Flash ActionScript交互实现

在开发过程中,经常需要在C++和Flash ActionScript之间进行数据交换和函数调用。本文将介绍如何实现这一功能,包括ActionScript部分的编写、C++代码的事件处理、结果返回以及如何从C++调用ActionScript。

在寻找能够播放Shock Wave Flash (.swf) 文件并使用ActionScript的C++代码时,发现了Igor Akarov的文章,但该文章并未提供调用和回调的支持。虽然Flash的ExternalInterface有大量文档,但很难找到一个实际工作的示例。因此,对其进行了扩展,并认为这可能对其他人也有用。

使用代码

由于Flash使用XML在ExternalInterface之间传递参数,决定使用TinyXML库。该库包含在示例代码中。

让从ActionScript部分开始。在文件"HelloWorld.as"中,有一行代码告诉Flash的ExternalInterface注册一个回调:

public function onSetButtonText(arg:String):String { button.setLabel(arg); return "OK"; }

上述代码注册了一个名为onSetButtonText的ActionScript函数,可以通过名称setButtonText从例如JavaScript(如果容器是Web浏览器)或C++(在这个例子中)调用。

每次用户在Flash ActionScript中点击按钮时,都会调用mouseDownHandler。为了动画效果,它改变了x和y坐标,并调用count()获取按钮的新文本:

private function mouseDownHandler(event:MouseEvent):void { button.x += 1; button.y += 1; button.setLabel(count()); }

下面是一个如何从ActionScript调用Flash ExternalInterface的示例。它调用了addNumbers函数。在接下来的段落中描述了如何在C++代码中处理这个调用:

public function count():String { ExternalInterface.marshallExceptions = true; try { counter = ExternalInterface.call("addNumbers", counter, 1); return String(counter); } catch (e:Error) { return e.toString(); } return String("Error"); }

如前所述,代码被重用。函数CFlashWnd::Invoke已经增强,以便理解从Flash发出的事件。如果所有参数都正确,它将调用FlashCall方法。

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); } } }

CFlashWnd::FlashCall然后进行繁重的工作,即解包XML。通过调用Tiny XML库函数doc.Parse解析请求。Flash通过元素传递调用细节。它通过hDoc.FirstChildElement("invoke")查找。调用的函数名称在元素的"name"属性中指定。它通过调用QueryStringAttribute查找。如果所有信息都正确,整个元素树将传递给addNumbers方法。

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); doc.Parse(c_str); delete[] c_str; TiXmlHandle hDoc(&doc); TiXmlElement *pInvokeElement = hDoc.FirstChildElement("invoke").Element(); if (pInvokeElement != NULL) { std::string functionName; int result = pInvokeElement->QueryStringAttribute("name", &functionName); if (result == 0) { if (functionName == "addNumbers") { hr = addNumbers(pInvokeElement); } } } } return hr; }

现在CFlashWnd::FlashCall能够解码被调用的函数名称。接下来,让看看如何解码函数参数并将函数结果(返回值)作为数字传递回Flash对象(ExternalInterface):

HRESULT CFlashWnd::addNumbers(TiXmlElement *pInvokeElement) { HRESULT hr = E_INVALIDARG; 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"%d", number1 + number2); hr = m_lpControl->SetReturnValue(result); } } } return hr; }

下面是一个如何从C++调用ActionScript的简单示例。注意,必须在ActionScript中调用了ExternalInterface.addCallback,否则会失败!

BSTR _result = m_lpControl->CallFunction(L"Click me!");

构建Flash ActionScript

要将.as文件编译成.swf文件,以便Flash播放器播放,使用了Adobe的免费mxmlc编译器。可以从他们的网站下载。

要将其作为Visual Studio项目的一部分构建,请添加自定义构建规则:

"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
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485