home > 過去ログ(2004年以前) > fscommand + Visual Basicでマルチユーザ
2001/12/25

fscommand + Visual Basicでマルチユーザ


サンプルパッケージダウンロード

目次


  • 背景
    このページでは、Webからすこし離れて、FlashをWindowsアプリケーションのインターフェース構築に使う場合のマルチユーザ化について解説します。Windowsアプリケーションなど作る予定はない! という方は読む必要はありません。FlashムービーはWindowsのShockwave Flashコンポーネントを用いてWindowsアプリケーションから読み込むことができます。 読み込まれた後でもFlashのほとんどの機能はそのまま有効ですが、Flashの中でXMLSocketオブジェクトを使っている場合、XMLSocketの機能は使えなくなってしまいます。Windowsプログラムの枠を飛び越えてソケット接続を確立することはできないということです。そこで、XMLSocketを使っているFlashムービーをVisual Basic(以下VB)で読み込んだときに、ソケット機能とXML処理をVBで代替する例を以下で説明します。 このチュートリアルの筆者がなんでこんなことを試みたかというと、FACEsサーバの専用ゲームロビーとして、Windowsの常駐アプリケーションを用意しようという計画があるからです。目的はなんであれ、読まれた方のお役に立てば幸いです。

    目次に戻る

  • fscommandとは
    fscommandはFlashムービーがFlashのブラウザに対してメッセージをおくるためのActionScript関数です。パラメータとしてcommand, argumentsの二つを指定できます。Web上でFlashを使う場合はJavaScriptに対してメッセージを送る場合によく使用されますが、今回のサンプルでは、VBで制作したWindowsプログラムに対してメッセージを送ります。

    目次に戻る

  • flaのコード解説
    以下はWindowsプログラムから読み込むサンプルFlashムービー内のActionScriptの解説です。このサンプルはFACEsサーバのダウンロードパッケージに含まれているtest.flaの内容とほとんど同じで、このムービー単独でもサーバに接続できますが、VBに埋め込まれてXMLSocketが機能しなくなったときにfscommandを使用するようになっているところが大きく違うところです。以下、test.flaとの違いについて主に解説していきます。

    以下の二つのスクリプトはマウスにくっついて動く白丸用のスクリプトで、FACEsサーバパッケージ付属のtest.flaとおなじです。sendPosという関数を用意してマウスの位置を送信していますが、sendPosの機能は後で説明するように、Flashプレーヤー上とWindowsプログラムの中では動作が異なります。
    
     1:         onClipEvent (mouseMove) {
     2:            if (_root.selfname == "1") {
     3:               _root.sendPos("1", _root._xmouse, _root._ymouse);
     4:            }
     5:         }
    
    
     1:         onClipEvent (mouseMove) {
     2:            if (_root.selfname == "2") {
     3:               _root.sendPos("2", _root._xmouse, _root._ymouse);
     4:            }
     5:         }
    


    この関数は、test.flaにはありませんが、今回のサンプルはボタンを押したときにサーバへの接続を行うようになっているので、ボタンに対するコールバック関数として用意されています。
    
     1:      function startApp () {
     2:         str = "<QN app=\"test\"/>";
     3:         sendStr(str);
     4:      }
    


    loadEnd関数はtest.flaと同じです。が、XMSocketオブジェクトはそのFlashムービーがWindowsプログラムから読み込まれている場合機能しないので、必ず接続に失敗します。なので、onConnectで呼ばれるコールバック関数の中で、接続に成功したかどうかをチェックしなければなりません。
    
     1:      function loadEnd () {
     2:         mySocket = new XMLSocket();
     3:         mySocket.onConnect = checkConnect;
     4:         mySocket.connect("localhost", 8080);
     5:         mySocket.onClose = checkClose;
     6:      }
    


    checkConnect接続時のコールバック関数で、接続が失敗しても呼ばれるので、ここでSckという変数にXMLSocketでの接続が成功(Windowプログラムから呼ばれてない)したか失敗(Windowsプログラムから呼ばれている)したかの判定結果をBooleanでいれておきます。
    
     1:      function checkConnect (bOK) {
     2:         if (bOK) {
     3:            mySocket.onXML = getData;
     4:            Sck = new Boolean(true);
     5:            trace ("trueconnection");
     6:         } else {
     7:            Sck = new Boolean(false);
     8:            trace ("falseconnection");
     9:         }
    10:      }
    


    接続が切断されたときのコールバック関数です。XMLSocketでの接続が成功している場合は接続をソケットをcloseする必要がありますが、失敗しているときはcloseしてもしょうがない(そもそもconnectしていない)ので、fscommandでquitというコマンドを外部に送っています。quitというコマンドはFlash Playerに対しては終了コマンドとして作用するので、Flash Playerでこのムービーを開いている場合は、Flash Player自体が終了します。
    
     1:      function closeSocket () {
     2:         if (Sck) {
     3:            mySocket.close();
     4:         } 
     5:         fscommand ("quit");
     6:         trace ("closeSocket test\n");
     7:      }
    


    XMLオブジェクトを送信する関数です。XMLSocketで接続されているときはtest.flaと同じですが、Windowsプログラムから呼ばれているときには、Sendというコマンドを定義してfscommandでXMLオブジェクトを構成する文字列を外部プログラムに送っています。
    
     1:      function sendStr (str) {
     2:         if (Sck) {
     3:            theXML = new XML();
     4:            theXML.parseXML(str);
     5:            mySocket.send(theXML);
     6:         } else {
     7:            fscommand ("Send", str);
     8:         }
     9:      }
    
    目次に戻る

  • VBのコード解説
    さてこんどはVBのコードの解説です。行番号は通しで付けています。このVBプログラムは、Project1というプロジェクト名になっていますがProject1には、4つのオブジェクトがあり、それぞれ、Form1(Form)、swfObj(ShockwaveFlash)、Timer1(Timer)、Winsock1(Winsock)という名前になっています(括弧内はコンポーネント名)。また参照設定を見ていただくとわかりますが、XML解析のために、MSXML 4.0というDLLを使用しています。ダウンロードはMicrosoftのサイト を参照してください。

    4行目からのForm_Load()関数では、起動時の処理を行っています。vbtest.swf(vbtest.flaから生成されたSWFファイル) を読み込み、FACEsサーバプログラムが走っているマシンの名前とポート番号を指定し、接続を行っています。ここでは、サーバパッケージ付属のサンプルとおなじ、localhost、ポート8080に接続しています。
    
     1: Option Explicit
     2: Dim con As Integer
     3: 
     4: Private Sub Form_Load()
     5:     Dim tPath As String
     6:     
     7:     tPath = CurDir & "\vbtest.swf"
     8:     swfObj.Movie = tPath
     9:     
    10:     Winsock1.RemoteHost = "localhost"
    11:     Winsock1.RemotePort = 8080
    12:     Winsock1.Connect
    13:     con = 1
    14: End Sub
    15: 
    


    SWFファイルから発行されたfscommandを解釈します。quitというコマンドはFlash Playerではデフォルトで停止コマンドとして解釈されますが、この例はオリジナルアプリケーションですので、アプリケーションの終了処理を書く必要があります。あと、サーバへのXMLオブジェクト送信用にSendというコマンドを独自に定義して使用しているので、Send専用の処理を書いています。
    
    16: Private Sub swfObj_FSCommand(ByVal tCmdstr As String, _
    17:			ByVal tArgstr As String)
    18: 
    19:     If (tCmdstr = "quit") Then
    20:         Winsock1.Close
    21:         Winsock1.LocalPort = 0
    22:         Call EnableTimer
    23:         con = 0
    24:     ElseIf (tCmdstr = "Send") Then
    25:         SendStr tArgstr
    26:     End If
    27:   
    28: End Sub
    29: 
    


    アプリケーション終了のタイミング調整にTimerを使っているので、その関連処理です。
    
    30: Private Sub EnableTimer()
    31:   Timer1.Enabled = True
    32: End Sub
    33: 
    34: Private Sub Timer1_Timer()
    35:   Unload Me
    36: End Sub
    37: 
    


    fscommandによってswfからSendコマンドが送られて来たときのために、SendStrという関数を用意しています。WinsockのSenddataメソッドで、文字列をFACEsサーバに送信しています。XMLSocket(とFACEsサーバ)は0バイト文字(VBではvbNullChar)をXMLオブジェクトの終端文字として解釈するので、送信時にvbNullCharを付加しています。
    
    38: Private Sub SendStr(str As String)
    39:     If con = 1 Then
    40:         Winsock1.SendData str & vbNullChar
    41:     End If
    42: End Sub
    43: 
    


    サーバからXMLオブジェクトを受信したときの処理です。Workという文字列変数に保存して、XMLオブジェクトとしての処理を次で定義しているProcessXMLという関数で行っています。
    
    44: Private Sub Winsock1_DataArrival(ByVal bytesTotal As Long)
    45:     Dim Work As String
    46:     Winsock1.GetData Work
    47:     ProcessXML Work
    48: End Sub
    49: 
    


    サーバから受信した文字列の処理を行っている関数です。引数文字列をXMLドキュメントとしてロード、パースし、ルートノードの名前と属性値に応じて処理を分岐しています。処理内容としては、test.flaのgetData関数で行っていることをそのまま代替しています。VBプログラム側からswfの関数を直接呼び出す方法がない(もしくは見つからない)ので、Shockwave Flashコンポーネントの、TSetPropertyメソッドとSetVariableメソッドを用いて同等の処理を実現しています。
    
    50: Private Sub ProcessXML(str As String)
    51:     Dim xml As DOMDocument
    52:     Dim docRoot As IXMLDOMNode
    53:     Dim n As String
    54:     Dim x As Double
    55:     Dim y As Double
    56: 
    57:     Set xml = New DOMDocument
    58:     xml.loadXML str
    59:     Set docRoot = xml.documentElement
    60:     
    61:     If (StrComp(docRoot.nodeName, "P", vbTextCompare) = 0) Then
    62:       If docRoot.Attributes.getNamedItem("n").nodeTypedValue = "1" Then
    63:             swfObj.TSetProperty "_root.mouse1", 0, _
    64:		docRoot.Attributes.getNamedItem("x").nodeTypedValue
    65:             swfObj.TSetProperty "_root.mouse1", 1, _
    66:		docRoot.Attributes.getNamedItem("y").nodeTypedValue
    67:       ElseIf docRoot.Attributes.getNamedItem("n").nodeTypedValue = "2" Then
    68:             swfObj.TSetProperty "_root.mouse2", 0, _
    69:		docRoot.Attributes.getNamedItem("x").nodeTypedValue
    70:             swfObj.TSetProperty "_root.mouse2", 1, _
    71:		docRoot.Attributes.getNamedItem("y").nodeTypedValue
    72:       End If
    73:     ElseIf (StrComp(docRoot.nodeName, "N", vbTextCompare) = 0) Then
    74:         swfObj.SetVariable "_root.selfname", _
    75:		docRoot.Attributes.getNamedItem("n").nodeTypedValue
    76:     ElseIf (StrComp(docRoot.nodeName, "D", vbTextCompare) = 0) Then
    77:       If docRoot.Attributes.getNamedItem("n").nodeTypedValue = "1" Then
    78:             swfObj.TSetProperty "_root.mouse1", 0, 0
    79:             swfObj.TSetProperty "_root.mouse1", 1, 0
    80:       ElseIf docRoot.Attributes.getNamedItem("n").nodeTypedValue = "2" Then
    81:             swfObj.TSetProperty "_root.mouse2", 0, 0
    82:             swfObj.TSetProperty "_root.mouse2", 1, 0
    83:       End If
    84:     End If
    85: End Sub
    
    目次に戻る