65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.59/5 (23投票s)

2011年10月17日

CPOL

4分钟阅读

viewsIcon

85582

downloadIcon

4697

将 Flash 嵌入到您的应用程序中,并通过 C++ 与之通信。

引言

Flash 很棒,但它主要用于 Web。如何将 Flash 嵌入到您自己的应用程序中并与它们进行数据传输呢?

我发现很多人都讨论过这个主题,但有时他们的方法会因为某些原因而神秘地失败。这里有一个功能齐全且非常简单的项目。

1.png

背景

本文假设您熟悉 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.FLA1.SWF Flash 源文件和影片
  • AX.H / AX.CPP ActiveX Win32 接口
  • MAIN.CPP 演示了我们到目前为止所说的一切。
  • 其他解决方案文件,如 MAIN.RCX86.MANIFESTFUNC.H
  • 可执行文件,以防您厌倦打开 Visual Studio 来编译示例。

祝你好运。

历史

  • 2011-10-21:拼写错误,一些补充
  • 2011-10-17:首次发布
© . All rights reserved.