C++ 中的增强透明 Flash 控件






4.90/5 (15投票s)
使用 C++ 实现的 OLE 容器,用于托管 Flash Player 控件,支持 C++ 和 Flash ActionScript 之间的调用和回调。

引言
本文基于 Makarov Igor 撰写的优秀文章。它扩展了功能,支持 C++ 和 Flash ActionScript
之间的调用和回调。
背景
由于我正在寻找一些(C++)代码来播放带有 ActionScript 的 Shock Wave Flash (.swf) 文件,所以我找到了上面引用的文章。但是,它不支持调用和回调。关于 Flash ExternalInterface
的文档很多,但我发现很难找到一个可用的示例。所以我添加了它,并认为它对其他人也可能有用。
Using the Code
由于 Flash 在 ExternalInterface
上使用 XML 来序列化参数来回传递,所以我决定使用 TinyXML
库。它包含在示例代码中。
第一部分. Flash ActionScript
让我们从 ActionScript
部分开始。在 "HelloWorld.as" 文件中,有一行告诉 Flash 的 ExternalInterface
注册一个回调
// 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);
上面的代码使用名称 onSetButtonText
注册了 ActionScript
函数,该函数可以从例如 JavaScript(如果容器是 Web 浏览器)或 C++(在本例中)通过名称 setButtonText
调用。
函数 onSetButtonText
仅用于演示目的,它简单地设置按钮的文本
public function onSetButtonText(arg:String):String {
button.setLabel(arg);
return "OK";
}
每次用户在 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++ 代码中处理此调用的方法。
// 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");
}
第二部分. C++ 代码中的事件处理
如前所述,代码是重用的。函数 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 在 <invoke>
XML 元素中传递调用详细信息。它通过 hDoc.FirstChildElement("invoke")
查找。调用函数的名称在 <invoke>
元素的 "name
" 属性中指定。它通过调用 QueryStringAttribute
来查找。如果所有信息都正确,整个元素树将被传递给 addNumbers
方法。
// 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;
}
上面的代码展示了一种处理来自 Flash ActionScript
的函数调用请求的非常简单的方法。如果您想处理更多调用,请随时改进。毕竟,这只是演示了机制的基础。
第三部分. 将结果从 C++ 返回到 ActionScript
因此,CFlashWnd::FlashCall
现在能够解码被调用的函数名。现在,让我们看看如何解码函数参数并将函数结果(返回值)作为数字返回给 Flash 对象(ExternalInterface
)
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;
}
上面的代码展示了如何通过调用 ActiveX 接口上的 SetReturnValue
将结果返回给 Flash。它还展示了如何使用 Tiny XML 库中的函数来获取所需的参数值。
第四部分. 从 C++ 调用 ActionScript
下面展示了一个从 C++ 调用 ActionScript
的简单示例。请注意,必须在 ActionScript
中调用 ExternalInterface.addCallback
,参见第一部分,否则将会失败!
BSTR _result = m_lpControl->CallFunction(L"<invoke name=\"setButtonText\"
returntype=\"xml\"><arguments><string>Click me!</string></arguments></invoke>");
构建 Flash ActionScript
要将 .as 文件编译为 Flash 播放器可以播放的 .swf 文件,我使用了 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
致谢
特别感谢以下作者
- 纯 C++ 中的透明 Flash 控件
- Tiny XML
- 一个未知的来源,为
ActionScript
提供了起点
没有他们,编写代码将更加困难!
法律事宜
不幸的是,我们生活在一个这样的消息是不可避免的世界……
本文和源代码已提供给您随意使用,不提供任何保证!本文和源代码仅演示基本原理,不应用于可能对人、动物造成伤害或带来任何风险的情况。请自行承担使用风险,我概不负责。我不能承担责任,您已被警告。
很抱歉,我希望这听起来不会太冒犯。因为归根结底,编码应该是有趣的!
历史
- 2011 年 4 月 8 日:首次发布