外部 API 範例:在 ActionScript 和使用 ActiveX 控制項的桌面應用程式之間通訊

Flash Player 9 和更新的版本

這個範例將示範如何使用外部 API,在 ActionScript 與使用 ActiveX 控制項的桌面應用程式之間進行通訊。這個範例會再次使用 Introvert IM 應用程式,其中包括 ActionScript 程式碼,甚至是相同的 SWF 檔,因此將不再說明如何在 ActionScript 中使用外部 API。熟悉上一個範例將有助於瞭解這個範例。

這個範例中的桌面應用程式是使用 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_tw。您可以在 Samples/IntrovertIM_CSharp 檔案夾中找到 Introvert IM C# 檔案,此應用程式是由下列檔案組成:

檔案

說明

AppForm.cs

具有 C# Windows Form 介面的主應用程式檔案。

bin/Debug/IntrovertIMApp.swf

應用程式所載入的 SWF 檔。

ExternalInterfaceProxy/ExternalInterfaceProxy.cs

類別,做為 ActiveX 控制項的包裝函式,以便進行「外部介面」通訊。它提供的機制可以讓您透過 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 建立的包裝函式組件,這些是透過 Managed 程式碼存取 Flash Player (Adobe Shockwave® Flash) ActiveX 控制項必要的項目。

Introvert IM C# 應用程式概觀

這個樣本應用程式代表兩個相互通訊的即時傳訊用戶端程式 (一個在 SWF 檔內,另一個是使用 Windows Form 建立)。使用者介面包括 Shockwave Flash ActiveX 控制項的實體,在其中會載入包含 ActionScript IM 用戶端的 SWF 檔。這個介面也包括了一些組成 Windows Form IM 用戶端的文字欄位:用來輸入訊息的欄位 (MessageText)、用來顯示在用戶端之間傳送訊息記錄的欄位 (Transcript) 以及用來顯示在 SWF IM 用戶端中設定之可用性狀態的欄位 (Status)。

包括 Shockwave Flash ActiveX 控制項

如果要在 Windows Form 應用程式中包含 Shockwave Flash ActiveX 控制項,您必須先將它加入「Microsoft Visual Studio 工具箱」。

若要將控制項加入工具箱:

  1. 開啟「Visual Studio 工具箱」。

  2. 在 Visual Studio 2003 的 Windows Form 部分或 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 容器應用程式通訊的方式和與網頁瀏覽器通訊的方式相當類似。如先前內容所述,當 ActionScript 與網頁瀏覽器進行通訊時,在開發人員查覺之前,都是直接呼叫函數;而函數呼叫與回應如何格式化並在播放程式與瀏覽器之間傳遞的詳細資訊則會隱藏。然而,當外部 API 是用來與 ActiveX 容器應用程式進行通訊時,Flash Player 就會使用特定的 XML 格式將訊息 (函數呼叫與傳回值) 傳送給應用程式,同時也預期來自容器應用程式的函數呼叫與傳回值會使用相同的 XML 格式。ActiveX 容器應用程式的開發人員必須撰寫程式碼,讓程式碼瞭解這些格式,並以正確的格式建立函數呼叫和回應。

Introvert IM C# 範例包括一組類別,可讓您避免將訊息格式化的情形;而您也可以在呼叫 ActionScript 函數以及透過 ActionScript 接收函數時,改用標準的資料類型。ExternalInterfaceProxy 類別可以和其它 helper 類別協同作業以提供這項功能,並且可以在任何 .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() 方法來接收 proxy 的 ExternalInterfaceCall 事件。這個事件是在從 Flash Player 發出函數呼叫時,由 ExternalInterfaceProxy 類別傳送。訂閱這個事件是 C# 程式碼接收並回應來自 ActionScript 的函數呼叫時所使用的方式。

當函數呼叫是來自 ActionScript 時,ExternalInterfaceProxy 實體 (proxy) 會接收該呼叫、轉換它的 XML 格式,並通知物件這是 proxy 之 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 類別

使用 proxy 來包裝 ActiveX 控制項可能並不一定實用,也許您想自行撰寫 proxy 類別 (例如,使用不同的程式語言或者目標是針對不同的平台)。雖然這裡並沒有詳細說明如何建立 proxy,但是對於瞭解這個範例中 proxy 類別的內部作業仍然是有幫助的。

您可以使用 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 控制項。ActionScript 函數呼叫是由 CallFunction() 方法所發出。這個方法會使用一個參數 (在本範例中為 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 類別中,這個 request 會從 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():將收到的 XML 解碼為呼叫 ActionScript 函數的結果。

這些方法會將 C# 值編碼為外部 API 的 XML 格式,並將 XML 解碼為 C# 物件。如需 Flash Player 所使用之 XML 格式的詳細資訊,請參閱外部 API 的 XML 格式