C++ 与 Flash:使用 C++ 和 ActiveX 在 Win32 中与 SWF 进行数据交互






4.59/5 (23投票s)
将 Flash 嵌入到您的应用程序中,并通过 C++ 与之通信。
引言
Flash 很棒,但它主要用于 Web。如何将 Flash 嵌入到您自己的应用程序中并与它们进行数据传输呢?
我发现很多人都讨论过这个主题,但有时他们的方法会因为某些原因而神秘地失败。这里有一个功能齐全且非常简单的项目。

背景
本文假设您熟悉 C++ 和 COM。请确保您回顾了这些主题,并查阅我的 Win32 ActiveX 文章。您也可以使用 MFC 或 ATL 来插入 ActiveX 控件,而无需处理真正混乱的 COM 实现。本文还假设您了解托管 ActiveX 控件并连接到它以接收通知的机制,尽管我的 AX.CPP 代码包含了所有必需的函数,但这些函数在本文中并未详细讨论。
此外,还需要 ActionScript 3.0 知识。
创建 ActiveX 控件
您可能已经在实现自己的方法来将 ActiveX 控件插入到您的应用程序中,如果是这样,您就不需要使用我的 AX.CPP 来获取 IShockwaveFlash
指针。要插入 "Shockwave.Flash
" ActiveX 控件,我使用了 Win32 ActiveX 文章的讨论和 AX.CPP,它仅实现了一个 IOleClientSite,允许我在资源文件中使用类 ID
CONTROL "{D27CDB6E-AE6D-11CF-96B8-444553540000}", 888,
"AX", WS_CHILD | WS_VISIBLE, 10, 9, 399, 206
以便创建一个 "AX
" 控件(它将请求的 ActiveX 控件的类 ID 作为窗口标题)。一旦我们有了 HWND
,我就可以向它发送一个 AX_QUERYINTERFACE
来获取指向 IShockwaveFlash
: 的指针:
CLSID iidx = __uuidof(IShockwaveFlash);
IShockwaveFlash* p = 0;
HRESULT hr = (HRESULT)SendMessage(hX,AX_QUERYINTERFACE,(WPARAM)&iidx,(LPARAM)&p);
当然,您的方法可能是 ATL 或类似的。最后要做的就是激活控件的就地编辑。
SendMessage(hX,AX_INPLACE,1,0);
加载 SWF
我只是将资源中的 "1.swf" 提取到一个临时文件中并加载它(以及一个白色背景颜色)。
_bstr_t x(df);
p->put_BackgroundColor(RGB(255,255,255));
p->put_Movie(x);
将数据发送到 SWF
注册 ActionScript 函数
提出了许多方法,我将使用最简单、最高效的方法:从 C++ 代码调用 ActionScript 3.0 函数。首先,让我们在 .FLA 文件(在第 1 帧)中定义一个 ActionScript
函数。
import flash.external.ExternalInterface;
// The following is called from our host
function TestFunction1(he:String)
{
this.gotoAndPlay(2);
}
// Register TestFunction1 to be called
flash.external.ExternalInterface.addCallback("foo1",TestFunction1);
这里有什么?仅仅是一个名为 "TestFunction1
" 的函数,它接受一个 String
参数(此函数仅跳转到第 2 帧,不使用传递的 string
,但传递它以便您了解如何将参数传递给函数)。
之后,我们必须调用 flash.external.ExternalInterface.addCallback
并将 "TestFunction1
" 注册为一个可以被我们的容器调用的函数。此函数将以 "foo1
" 的名称可见。您可以将其类比为 DEF 文件中的 "EXPORTS
" 部分。
调用函数
IShockwaveFlash*
有一个 CallFunction
成员,我们可以调用它。很简单:Flash 期望调用的实体作为带有 "name
" "foo1
" 的 XML 元素传递,参数以 XML 格式传递。您可以在这个 Adobe 帮助链接 中了解 Flash 期望的 XML 格式。
我的代码中的 WM_COMMAND
处理程序演示了所有这些,并且调用如下所示:
_bstr_t fu(L"<invoke name=\"foo1\" returntype=\"xml\">
<arguments><string>Hello</string></arguments></invoke>");
_bstr_t rs = p->CallFunction(fu);
获取事件通知
好的,我们已经调用了一个 AS 3.0 函数,但 AS 3.0 函数如何调用我们呢?很简单——是的,您已经猜到了——通过 IDispatch。
首先,我们使用标准的 ActiveX 建议机制来注册通知——请参阅 AX.CPP 以及对 AXConnectObject
的调用(您也可以使用自己的 MFC/ATL 方法进行连接)。我们传递我们自己的 IDispatch
实现,该实现除了标准的 IUnknown
和 IDispatch
方法外,还实现 IDispatch::Invoke
如下:
HRESULT _stdcall Invoke(DISPID d,REFIID ,LCID ,WORD ,DISPPARAMS* p,
VARIANT FAR*,EXCEPINFO FAR* ,unsigned int FAR*)
{
if (d != 0xC5) // DISPID for "Flash Call"
return S_OK;
if (!p)
return E_POINTER;
if (p->cArgs != 1)
return E_INVALIDARG;
if (p->rgvarg[0].vt != VT_BSTR)
return E_INVALIDARG;
wstring w = p->rgvarg[0].bstrVal;
MessageBox(0,w.c_str(),L"Message",MB_ICONINFORMATION);
return S_OK;
}
让我们来解释一下。我们检查 dispid 是否为 0xC5,即 "FlashCall
" 函数。此函数通过我们的 IDispatch
从 ActionScript
调用,并传递一个带有调用参数的 BSTR
。正如您可能已经猜到的,这与我们之前在我的代码中使用的 XML 格式相同。我只是在 MessageBox
中显示结果——当然,您希望使用我的 XML 库来解析它并处理函数调用。
下面是我们从 ActionScript 3.0 调用函数的方式:
// Listener for b2
function Act2(et:Event):void
{
flash.external.ExternalInterface.call("ext2",2);
}
这是我们创建的第二个按钮的监听器。在这种情况下,"ext2
" 将作为 <invoke>
元素中的 "name
" 变量传递,而数字 '2
' 将作为 <arguments>
中的 <number>
元素传递。
x64 兼容性
如果您安装了 Flash x64 ActiveX(用于 Internet Explorer),这也将起作用。Flash 对 x64 的支持非常新,对于复杂的 AS 函数,您可能会遇到问题,但最终一切都会正常工作。
代码
有点粗糙(就像我所有的 CodeProject 文章一样 ;) 但它能用。zip 文件包含:
- 用于 Visual Studio 2008 或更高版本的项目文件 SLN 和 VCPROJ
- 1.FLA 和 1.SWF Flash 源文件和影片
- AX.H / AX.CPP ActiveX Win32 接口
- MAIN.CPP 演示了我们到目前为止所说的一切。
- 其他解决方案文件,如 MAIN.RC、X86.MANIFEST 和 FUNC.H。
- 可执行文件,以防您厌倦打开 Visual Studio 来编译示例。
祝你好运。
历史
- 2011-10-21:拼写错误,一些补充
- 2011-10-17:首次发布