.NETアプリからPaSoRiを使ってFeliCaカードを読み取ってみる(felica_for_vb.dllを使わない版)
ちょっと思いつきでやってみたのでメモ。
経緯
- 自分のPC、なにかのアプリがポート10250でListenしている(#゚Д゚)
- FeliCa Proxy Service…って、PaSoRiのドライバを入れたときに入ったものか*1
- 昔はfelica_for_vb.dllを使って遊んだけど、今ってドライバに付属していないの(・ω・)?
- その代わりに、FeliCa Proxy Serviceに接続してコマンド送れば制御できるってことかしら
- SDK for FeliCa & Adobe AIR / Adobe Flash Basicが無償で使えるのね(・∀・)
- 通信内容を覗いてみたら、最初はXMLで通信してるけど、認証後のデータはバイナリでした
- 解析するのは面倒なので終了(´・ω・`)…
- …っというのも何か悔しいので、無理矢理使い方を考えてみる(`・ω・´)
- Flashから通信できるのであれば、Flash.ocxをホストしたアプリケーションからのPaSoRiの使用も可能ジャネ( ゜Д゜)?
- このやりかたと同じでいけるし
概念図。
っというわけで、やってみた(・∀・)
Flash(swf)の作成
Flash(swf)のファイルはFlexを使って作成してみました。
ソースはこんな感じ(・∀・)
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" initialize="init(event)"> <mx:Script> <![CDATA[ import com.sony.jp.felica.FeliCaControl; import com.sony.jp.felica.event.OpenStatusEvent; import com.sony.jp.felica.FeliCaPollingAndGetCardInformationRequest; import com.sony.jp.felica.FeliCaPollingAndGetCardInformationResponse; import com.sony.jp.felica.event.FeliCaStatusEvent; import com.sony.jp.felica.error.FeliCaAccessError; import com.sony.jp.felica.FeliCaOpenReaderWriterAutoRequest; import com.sony.jp.felica.FeliCaOpenReaderWriterAutoResponse; import com.sony.jp.felica.event.FeliCaStatusEvent; import com.sony.jp.felica.error.FeliCaAccessError; private var fc:FeliCaControl = new FeliCaControl(); // 初期化 private function init(event:Event):void { ExternalInterface.addCallback( "open", open ); ExternalInterface.addCallback( "openReaderWriterAuto", openReaderWriterAuto ); ExternalInterface.addCallback( "pollingAndGetCardInformation", pollingAndGetCardInformation ); fc.addEventListener( OpenStatusEvent.OPEN_COMPLETE, onOpenComplete ); fc.addEventListener( OpenStatusEvent.OPEN_FAILURE, onOpenFailure ); fc.addEventListener( FeliCaStatusEvent.FELICA_ACCESS_COMPLETE, onFeliCaAccessComplete ); fc.addEventListener( FeliCaStatusEvent.FELICA_ACCESS_FAILURE, onFeliCaAccessFailure ); fc.addEventListener( FeliCaStatusEvent.FELICA_ACCESS_PARAMETER_ERROR, onFeliCaAccessParameterError ); } // 接続 private function open():void { fc.open(10250); } // SDK for FelICa SubSet コマンド open_reader_writer_auto() private function openReaderWriterAuto():void { var request:FeliCaOpenReaderWriterAutoRequest = new FeliCaOpenReaderWriterAutoRequest(); fc.access(request); } // SDK for FelICa : コマンド polling_and_get_card_information() private function pollingAndGetCardInformation():void { var request:FeliCaPollingAndGetCardInformationRequest = new FeliCaPollingAndGetCardInformationRequest(); request.systemCode = "FFFF"; fc.access(request); } private function onOpenComplete(event:OpenStatusEvent):void { ExternalInterface.call( "OpenComplete" ); } private function onOpenFailure(event:OpenStatusEvent):void { var error:Error = event.object as Error; ExternalInterface.call( "OpenFailure", error.errorID, error.message ); } private function onFeliCaAccessComplete(event:FeliCaStatusEvent):void { if (event.object is FeliCaOpenReaderWriterAutoResponse) { var openResponse:FeliCaOpenReaderWriterAutoResponse = event.object as FeliCaOpenReaderWriterAutoResponse; ExternalInterface.call( "OpenReaderWriterAuto", openResponse.felicaError, openResponse.rwError, openResponse.felicaProxyError ); } else if (event.object is FeliCaPollingAndGetCardInformationResponse) { var pollingResponse:FeliCaPollingAndGetCardInformationResponse = event.object as FeliCaPollingAndGetCardInformationResponse; ExternalInterface.call( "PollingAndGetCardInformation", pollingResponse.numberOfCards, pollingResponse.idm, pollingResponse.pmm, pollingResponse.felicaError, pollingResponse.rwError, pollingResponse.felicaProxyError ); } } private function onFeliCaAccessFailure(event:FeliCaStatusEvent):void { if (event.object is FeliCaAccessError) { var accessErr:FeliCaAccessError = event.object as FeliCaAccessError; ExternalInterface.call( "FeliCaAccessError", accessErr.errorID, accessErr.message, accessErr.felicaError, accessErr.rwError, accessErr.felicaProxyError ); } else if (event.object is Error) { var error:Error = event.object as Error; ExternalInterface.call( "Error", error.errorID, error.message ); } } private function onFeliCaAccessParameterError(event:FeliCaStatusEvent):void { var error:Error = event.object as Error; ExternalInterface.call( "Error", error.errorID, error.message ); } ]]> </mx:Script> </mx:Application>
やっていることは、ExternalInterfaceを使って、右から来たものを左へ、左から来たものを右へ受け渡しているだけ(´Д`)
FeliCaのライブラリの使い方については、SDK for FeliCa & Adobe AIR / Adobe Flashの中のドキュメントを参照してくださいな。
ホストアプリケーションの作成
そしてFlash.ocxを使用し、swfファイルをホストするアプリケーションの作成手順について。
とりあえずWindowsフォームアプリケーションを作って、ツールボックスアイテムの選択から、COMコンポーネントでFlash10.ocxを追加。
っで、ツールボックスに追加されたShockwave Flash Objectをフォームに貼り付け、VisibleをFalseに設定。
後は、Formのコードでこんな処理を書けば終了。
public partial class MainForm : Form { public MainForm() { InitializeComponent(); // Flashロード this.flashPlayer.LoadMovie( 0, Path.Combine( Application.StartupPath, "FelicaProxyClient.swf" ) ); this.flashPlayer.FlashCall += OnFlashPlayerFlashCall; } // open()呼び出し private void OnOpenButtonClick(object sender, EventArgs e) { this.flashPlayer.CallFunction( "<invoke name=\"open\" returntype=\"xml\"></invoke>" ); } // openReaderWriterAuto()呼び出し private void OnOpenReaderWriterAutoButtonClick(object sender, EventArgs e) { this.flashPlayer.CallFunction( "<invoke name=\"openReaderWriterAuto\" returntype=\"xml\"></invoke>" ); } // pollingAndGetCardInformation()呼び出し private void OnPollingAndGetCardInformationButtonClick(object sender, EventArgs e) { this.flashPlayer.CallFunction( "<invoke name=\"pollingAndGetCardInformation\" returntype=\"xml\"></invoke>" ); } // Flashからの通知 private void OnFlashPlayerFlashCall(object sender, _IShockwaveFlashEvents_FlashCallEvent e) { XmlDocument doc = new XmlDocument(); doc.LoadXml( e.request ); XmlAttribute attr = doc.DocumentElement.Attributes["name"]; if( attr.Value == "PollingAndGetCardInformation" ) { XmlNodeList list = doc.GetElementsByTagName( "arguments" ); string message = String.Format( "numberOfCards={0}\nidm={1}\npmm={2}\n", list[ 0 ].ChildNodes[ 0 ].InnerText, list[ 0 ].ChildNodes[ 1 ].InnerText, list[ 0 ].ChildNodes[ 2 ].InnerText ); MessageBox.Show( message ); } ... } }
作成したswfファイルをロードして、それ経由でFeliCa Proxy Serviceと通信してるわけですね(・ω・)
っで、めでたくカードの情報を読み取ることができました。
っというわけで、多少無理矢理ですが、.NETアプリケーションからの(Flash経由での)PaSoRiの使い方でした(・∀・)
ちょっとしたおもちゃなら、このやり方もありかな(・ω・)?
*1:ついでに、このサービス.NET製なのね。