外部 API 示例:在 ActionScript 和使用 ActiveX 控件的桌面应用程序之间进行通信

Flash Player 9 和更高版本

本示例说明了如何使用外部 API 在 ActionScript 与使用 ActiveX 控件的台式机应用程序之间进行通信。此示例再次使用了 Introvert IM 应用程序(包括 ActionScript 代码乃至相同的 SWF 文件),因此,不再说明外部 API 在 ActionScript 中的用法。熟悉上一个示例将有助于理解本示例。

本示例中的台式机应用程序是通过 Microsoft Visual Studio .NET 使用 C# 语言编写的。本示例的讨论重点是通过 ActiveX 控件使用外部 API 的特定方法。本示例说明如下技术:

  • 从承载 Flash Player ActiveX 控件的台式机应用程序调用 ActionScript 函数

  • 从 ActionScript 接收函数调用,并在 ActiveX 容器中处理它们

  • 使用 proxy 类来隐藏已序列化的 XML 格式的详细信息,Flash Player 使用该格式将消息发送到 ActiveX 容器

若要获取此范例的应用程序文件,请参阅 www.adobe.com/go/learn_programmingAS3samples_flash_cn。Introvert IM C# 文件位于 Samples/IntrovertIM_CSharp 文件夹中。该应用程序包含以下文件:

文件

说明

AppForm.cs

含有 C# Windows Forms 接口的应用程序主文件。

bin/Debug/IntrovertIMApp.swf

该应用程序加载的 SWF 文件。

ExternalInterfaceProxy/ExternalInterfaceProxy.cs

作为 ActiveX 控件的包装以进行 External Interface 通信的类。它为从 ActionScript 进行调用和接收调用提供了机制。

ExternalInterfaceProxy/ExternalInterfaceSerializer.cs

执行将 Flash Player 的 XML 格式消息转换为 .NET 对象的任务的类。

ExternalInterfaceProxy/ExternalInterfaceEventArgs.cs

此文件定义两个 C# 类型(类):一个自定义委托类和一个事件参数类,ExternalInterfaceProxy 类用它们来向侦听器通知来自 ActionScript 的函数调用。

ExternalInterfaceProxy/ExternalInterfaceCall.cs

此类是一个值对象,表示从 ActionScript 到 ActiveX 容器的函数调用,具有用于函数名和参数的属性。

bin/Debug/IntrovertIMApp.swf

该应用程序加载的 SWF 文件。

obj/AxInterop.ShockwaveFlashObjects.dll,

obj/Interop.ShockwaveFlashObjects.dll

Visual Studio .NET 创建的包装程序集,需要使用它们从托管代码访问 Flash Player (Adobe Shockwave® Flash) ActiveX 控件。

Introvert IM C# 应用程序概述

本范例应用程序代表两个相互通信的即时消息客户端程序(一个位于 SWF 文件中,而另一个则是使用 Windows Forms 构建的)。用户界面包含一个 Shockwave Flash ActiveX 控件的实例(在其中加载包含 ActionScript IM 客户端的 SWF 文件)。该接口还包含组成 Windows Forms IM 客户端的若干个文本字段:一个用于输入消息 (MessageText),一个用于显示在客户端之间发送的消息的文本 (Transcript),还有一个用于显示 SWF IM 客户端中设置的可用性状态 (Status)。

包含 Shockwave Flash ActiveX 控件

要将 Shockwave Flash ActiveX 控件包含在您自己的 Windows Forms 应用程序中,必须先将其添加到 Microsoft Visual Studio 工具箱中。

将控件添加到工具箱中:

  1. 打开 Visual Studio 工具箱。

  2. 右键单击 Visual Studio 2003 中的 Windows Forms 部分或 Visual Studio 2005 中的任何部分。在 Visual Studio 2003 中,从上下文菜单中选择“添加/移除项”(Visual Studio 2005 中为“选择项...”)。

    此操作将打开“自定义工具箱”(2003)/“选择工具箱项”(2005) 对话框。

  3. 选择“COM 组件”选项卡,该选项卡列出了计算机上所有可用的 COM 组件,包括 Flash Player ActiveX 控件。

  4. 滚动到 Shockwave Flash Object 并选择它。

    若没有列出此项,请确保在系统中安装了 Flash Player ActiveX 控件。

了解 ActionScript 与 ActiveX 容器间的通信

使用外部 API 与 ActiveX 容器应用程序进行的通信类似于与 Web 浏览器之间的通信,但有一个重要的不同之处。如前所述,当 ActionScript 与 Web 浏览器通信时,对于开发人员而言,只需直接调用函数即可;有关如何设置函数调用和响应格式以在播放器和浏览器间进行传递的详细信息都会被隐藏。然而,使用外部 API 与 ActiveX 容器应用程序进行通信时,Flash Player 以特定的 XML 格式向应用程序发送消息(函数调用和返回值),并要求来自容器应用程序的函数调用和返回值使用相同的 XML 格式。ActiveX 容器应用程序的开发人员编写的代码必须能够理解相应格式的函数调用和响应,以及应能够用相应格式创建它们。

Introvert IM C# 示例包含一组类,通过它们可以避免设置消息格式;相反,您可以在调用 ActionScript 函数和接收来自 ActionScript 的函数调用时,使用标准的数据类型。ExternalInterfaceProxy 类与其他辅助类一起提供该功能,并且可以在任何 .NET 项目中重复使用该类以便于进行外部 API 通信。

下面几段代码摘自主应用程序表单 (AppForm.cs),说明使用 ExternalInterfaceProxy 类实现的更为简化的交互过程:

public class AppForm : System.Windows.Forms.Form 
{ 
    ... 
    private ExternalInterfaceProxy proxy; 
    ... 
    public AppForm() 
    { 
        ... 
        // Register this app to receive notification when the proxy receives 
        // a call from ActionScript. 
        proxy = new ExternalInterfaceProxy(IntrovertIMApp); 
        proxy.ExternalInterfaceCall += new ExternalInterfaceCallEventHandler(proxy_ExternalInterfaceCall); 
        ... 
    } 
    ...

该应用程序声明和创建名为 proxy 的 ExternalInterfaceProxy 实例,传入对用户界面 (IntrovertIMApp) 中的 Shockwave Flash ActiveX 控件的引用。然后,代码注册 proxy_ExternalInterfaceCall() 方法以接收代理的 ExternalInterfaceCall 事件。当函数调用来自 Flash Player 时,ExternalInterfaceProxy 类将调度该事件。C# 代码接收和响应来自 ActionScript 的函数调用的途径便是订阅该事件。

当函数调用来自 ActionScript 时,ExternalInterfaceProxy 实例 (proxy) 接收调用,转换它的 XML 格式,并通知作为代理的 ExternalInterfaceCall 事件的侦听器的对象。对于 AppForm 类,由 proxy_ExternalInterfaceCall() 方法处理该事件,如下所示:

    /// <summary> 
    /// Called by the proxy when an ActionScript ExternalInterface call 
    /// is made by the SWF 
    /// </summary> 
    private object proxy_ExternalInterfaceCall(object sender, ExternalInterfaceCallEventArgs e) 
    { 
        switch (e.FunctionCall.FunctionName) 
        { 
            case "isReady": 
                return isReady(); 
            case "setSWFIsReady": 
                setSWFIsReady(); 
                return null; 
            case "newMessage": 
                newMessage((string)e.FunctionCall.Arguments[0]); 
                return null; 
            case "statusChange": 
                statusChange(); 
                return null; 
            default: 
                return null; 
        } 
    } 
    ...

该方法传递一个 ExternalInterfaceCallEventArgs 实例(在本例中名为 e)。而该对象具有一个 FunctionCall 属性,该属性是 ExternalInterfaceCall 类的实例。

ExternalInterfaceCall 实例是具有两个属性的简单值对象。FunctionName 属性包含 ActionScript ExternalInterface.Call() 语句中指定的函数名。如果在 ActionScript 中添加了任何参数,则这些参数都包含在 ExternalInterfaceCall 对象的 Arguments 属性中。在本例中,处理事件的方法只是一个 switch 语句,其作用类似于流量管理器。FunctionName 属性 (e.FunctionCall.FunctionName) 的值决定了将调用 AppForm 类的哪个方法。

先前代码清单中的 switch 语句的分支说明常见的方法调用情况。例如,任何方法都必须向 ActionScript 返回一个值(例如,isReady() 方法调用)或返回 null(就像其他方法调用那样)。在 newMessage() 方法调用(传递参数 e.FunctionCall.Arguments[0],即 Arguments 数组的第一个元素)中,说明了访问从 ActionScript 传递的参数的方法。

使用 ExternalInterfaceProxy 类从 C# 调用 ActionScript 函数比从 ActionScript 接收函数调用更为简单明了。若要调用 ActionScript 函数,请使用 ExternalInterfaceProxy 实例的 Call() 方法,如下所示:

    /// <summary> 
    /// Called when the "Send" button is pressed; the value in the 
    /// MessageText text field is passed in as a parameter. 
    /// </summary> 
    /// <param name="message">The message to send.</param> 
    private void sendMessage(string message) 
    { 
        if (swfReady) 
        { 
            ... 
            // Call the newMessage function in ActionScript. 
            proxy.Call("newMessage", message); 
        } 
    } 
    ... 
    /// <summary> 
    /// Call the ActionScript function to get the current "availability" 
    /// status and write it into the text field. 
    /// </summary> 
    private void updateStatus() 
    { 
        Status.Text = (string)proxy.Call("getStatus"); 
    } 
    ... 
}

如本例所示,ExternalInterfaceProxy 类的 Call() 方法非常类似于 ActionScript 中的对应方法 ExternalInterface.Call()。第一个参数是一个字符串,即要调用的函数的名称。任何其他参数(未在此处显示)也一起传递给 ActionScript 函数。如果 ActionScript 函数返回值,则由 Call() 方法返回该值(如前例所示)。

深入 ExternalInterfaceProxy 类内部

使用 ActiveX 控件的代理包装不一定总是切实可行的,或者您可能想自行编写代理类(例如,使用不同的编程语言或针对不同的平台)。尽管有关创建代理的所有细节不会在此一一介绍,但是了解本例中代理类的内部运作原理却非常有益。

可以使用 Shockwave Flash ActiveX 控件的 CallFunction() 方法,通过外部 API 从 ActiveX 容器中调用 ActionScript 函数。以下从 ExternalInterfaceProxy 类的 Call() 方法摘录的代码显示了此过程:

// Call an ActionScript function on the SWF in "_flashControl", 
// which is a Shockwave Flash ActiveX control. 
string response = _flashControl.CallFunction(request);

在摘录的这段代码中,_flashControl 为 Shockwave Flash ActiveX 控件。使用 CallFunction() 方法执行 ActionScript 函数调用。该方法具有一个参数(本例中为 request),该参数是一个包含 XML 格式指令(包括要调用的 ActionScript 函数名称及所有参数)的字符串。从 ActionScript 返回的任何值都被编码为 XML 格式字符串,并作为 CallFunction() 调用的返回值发送回来。在本例中,XML 字符串存储在 response 变量中。

从 ActionScript 接收函数调用是一个多步骤过程。来自 ActionScript 的函数调用会导致 Shockwave Flash ActiveX 控件调度它的 FlashCall 事件,因此要从 SWF 文件接收调用的类(如 ExternalInterfaceProxy 类)需要为该事件定义一个处理函数。在 ExternalInterfaceProxy 类中,该事件处理函数被命名为 _flashControl_FlashCall(),并进行了注册以便在类构造函数中侦听该事件,如下所示:

private AxShockwaveFlash _flashControl; 
 
public ExternalInterfaceProxy(AxShockwaveFlash flashControl) 
{ 
    _flashControl = flashControl; 
    _flashControl.FlashCall += new _IShockwaveFlashEvents_FlashCallEventHandler(_flashControl_FlashCall); 
} 
... 
private void _flashControl_FlashCall(object sender, _IShockwaveFlashEvents_FlashCallEvent e) 
{ 
    // Use the event object's request property ("e.request") 
    // to execute some action. 
    ... 
    // Return a value to ActionScript; 
    // the returned value must first be encoded as an XML-formatted string. 
    _flashControl.SetReturnValue(encodedResponse); 
}

该事件对象 (e) 具有一个 request 属性 (e.request),该属性是一个 XML 格式的字符串,它包含有关函数调用的信息,如函数名和参数。容器可以使用该信息来决定要执行哪些代码。在 ExternalInterfaceProxy 类中,请求从 XML 格式转换为一个 ExternalInterfaceCall 对象,该对象以更易于访问的形式提供相同的信息。ActiveX 控件的 SetReturnValue() 方法用于将函数结果返回给 ActionScript 调用方;必须再次以外部 API 所用的 XML 格式对结果参数进行编码。

ActionScript 与承载 Shockwave Flash ActiveX 控件的应用程序间的通信使用特定的 XML 格式对函数调用和值进行编码。在 Introvert IM C# 示例中,ExternalInterfaceProxy 类使应用程序表单中的代码能够直接对发送到 ActionScript 或从中接收的值执行运算,并忽略 Flash Player 所用的 XML 格式的细节。为了完成该操作,ExternalInterfaceProxy 类使用 ExternalInterfaceSerializer 类的方法来将 XML 消息实际转换为 .NET 对象。ExternalInterfaceSerializer 类具有四个公共方法:

  • EncodeInvoke():将函数名和 C# ArrayList 类型的参数编码为相应的 XML 格式。

  • EncodeResult():将结果值编码为相应的 XML 格式。

  • DecodeInvoke():对来自 ActionScript 的函数调用进行解码。FlashCall 事件对象的 request 属性被传递给 DecodeInvoke() 方法,而且它将调用转换为一个 ExternalInterfaceCall 对象。

  • DecodeResult():对作为 ActionScript 函数调用的结果接收的 XML 进行解码。

这些方法将 C# 值编码为外部 API 的 XML 格式,并将 XML 解码为 C# 对象。有关 Flash Player 所用 XML 格式的详细信息,请参阅外部 API 的 XML 格式