SyntaxHighlighter

2012年5月21日月曜日

mruby on EFI Shell

mruby on EFI Shell

mruby を 32bit, 64bit の EFI Shell 上で動かしてみました。

mruby

mruby は、Ruby の作者であるまつもとさんが開発されている「組込み向け軽量 Ruby」の実装です。

詳しくは ITPro の紹介記事などをご覧ください。

今回は、この mruby を EFI Shell 上で動かしてみました。

EFI と EFI Shell

EFI

EFI もしくは UEFI とは、BIOS の置き換えのために Intel などが中心となって策定したファームウェアの仕様です。

最近の PC はほぼ UEFI 対応していますが、だからといって、すべてのもので EFI Shell が立ち上げられるとは限りません。
また、UEFI Boot 自体も、まだそれほど一般的ではないかもしれません。
ベンダによっては、UEFI なのに、UEFI Native Boot ではなく Legacy Boot させている (つまり CSM Boot させている) ところも多いようです。

ただし、Windows 8 が出てくるころには、状況も変わってくると思います。

EFI Shell

詳しく書くときりがないので EFI の詳細については省略しますが、その仕様の中で、EFI Shell という DOS や bash のようなシェル環境が定義されており、実際にいくつかの UEFI Boot 対応 PC では、Firmware 内に組込まれています。

BIOS Setup 画面で Launch EFI Shell のような項目があれば、それが該当します。
また、EFI Shell バイナリを USB メモリなどから起動させることで起動することもできます。

で、今回、この EFI Shell 上で動くように mruby をコンパイルしてみました。

動作例とダウンロード

ダウンロードは GitHub から可能です。
展開して得られるバイナリのうち、mruby.efi は 32bit 用、mruby64.efi は 64bit 用です。

VMware Player 上で動かすと、以下のようになります。
図は [ 10, 2, 4, 1 ].sort.each{ |i| p i } を引数で直接指定して実行したところです。
ファイルを渡してももちろん動作します。

作業記録とソースコード

以下は、作業記録です。

ソースコード

EFI Shell アプリケーションを作るので、EDK と mruby の二つが必要です。

EDK は edk2_for_mruby として、 mruby は mruby_efi_shell として、どちらも GitHub 上に置いてあります。

まず、edk2_for_mruby をダウンロードして展開し、続いて AppPkg/Applications/mruby に mruby_efi_shell を展開します。
やったことがなかったので、サブモジュールなどの設定はまだしていません。

ビルド環境

少し古いですが、現在の Mac や Let's note を使い始める前に使っていた Ubuntu 9.10 (Karmic Koala) でビルドしました。
ただし、これはすでにサポート期限が切れているので、これから始める人は、12.X をインストールした方がよいでしょう。
(余談ですが、私の実機では、 12.X をインストールすると、画面の Refresh Rate がおかしくなったので、面倒になってインストールをやめました。)

また、32bit, 64bit いずれの mruby.efi をビルドする場合でも、32bit の Ubuntu で可能です。
ただし、64bit 版を試すには、VMware Player で 64bit の EFI をエミュレートできる必要があります。
よく分かっていませんが、64bit CPU を搭載している必要があるだろうと思います。また、 Intel-VT などが有効になっている必要があるかもしれません。

あとは、EDK の How to build を見ながら設定していきます。
Unix-like systems でのビルド方法にも、必要なライブラリ (build-essential など) が書かれているので、入れていなかったらインストールします。

ソースの変更

ビルドするために、いくつか変更を加えました。

詳しくは GitHub の履歴を見ていただければいいですが、悩んだのは EDK 側のバグでした。

EFI Application で C の標準ライブラリを使えるようにするためのラッパが用意されているのですが、その中の一つである StdLib/LibC/Main/Main.cmain 関数の宣言が間違っていました。

正確には、それを呼び出しているサンプルである AppPkg/Applications/Main/Main.c との整合性がとれておらず、呼び出し規約が異なったものになっていました。

そのため、偶然、32bit 環境では動作するのに、64bit では動作せず、かなり悩むはめになりました。

それ以外は、y.tab.c のように動的に生成されるものをいくつかあらかじめ作っておくなどをしました。

なお、EDK 側に関数が定義されていないものがあり、現状は math モジュールは除いてあります
今後、必要なら EDK 側に実装するなどして、対応しようと思います。

テスト環境

テスト環境には VirtualBoxVMware Player を用いました。

VirtualBox では、「システム」の「EFI を有効化」にチェックをすることで、Bootable Device がなければ、32bit の EFI Shell が自動で立ち上がります。

VMware Player では、*.vmx ファイルに、以下の行を加えることで EFI Boot させることができます。
efi は小文字にする必要があります。

firmware = "efi"

これで、 Bootable Device がなければ、EFI Shell が自動で立ち上がるはずです。
なお、私の環境では Network の部分でハングしていたので、 Network デバイスを削除しておきました。

以上で 32bit, 64bit ともにテストができるはずです。

今後

今後は、EFI の機能を簡単に呼べるようなライブラリを作っておこうと思います。

少なくとも、Boot Service, Runtime Service ぐらいは Ruby の関数として提供しようと思います。

可能なら、すでに EDK に入っている Python のように、mruby を EDK に含めてもらいたいです。

2012年5月5日土曜日

Subversion Ajax View

Subversion リポジトリを Ajax で見易く表示できるようにしてみました。

概要

以下が動作サンプルです。
ローカルに設置した mruby のソースを見ているところです。

Subversion リポジトリを公開しているサーバー側に設置するスクリプトです。
以下のような特徴があります。

  • サーバーサイドに置きますが、PHP, Ruby on Rails などのスクリプト環境を必要としません。 pure JavaScript で書かれています。
    そのため、ファイルを差し替えるなどすれば、 VisualSVN Server を Windows 上で動作させているような場合でも、見た目だけ容易に変更できると思います。
  • Ajax を活用しているので、静的なページ遷移を発生させずにスムーズなアクセスが可能です。
  • ログもブラウザ上で見ることができます。
  • 古いリビジョンも見ることができます。
  • 現在のところ、差分表示はできません。
    将来、対応するかは未定です。
  • Internet Explorer には対応していません。
    静的な従来の表示がされるだけです。今後、対応するかも未定です。

背景

最近は Subversion よりも、分散型の git や mercurial などが人気ですが、特に企業などではまだまだ Subversion を利用しているところも多いと思います。
特に、開発者ではない人達も閲覧する場合、ブランチが単なるディレクトリである、といったような Subversion の単純化された概念は受け入れられやすいように思います。

そのため、より Subversion を利用しやすくなればよいと思い、こんな拡張機能を作ってみました。

設置方法

詳しくは GitHub の README.md を見てください。
設置してみたいのによく分からないという方は、コメント欄などでお聞きください。

  1. ソースをダウンロードしてください。
    ダウンロードページから subversion_ajax_view.zip をダウンロードし、 Subversion リポジトリのあるサーバーの公開されたディレクトリに展開します。
    ここでは、例として /var/www/svn_ajaxview_dir に展開し、http://server/svn_ajaxview としてそのディレクトリにブラウザからアクセスできるとします。
  2. svn_ajaxview 以外の場所に置くときは、/var/www/svn_ajaxview_dir/svnindex.xsl を開き、中の link, script 要素の href, src の該当部分である二箇所を適宜修正してください。
    この時点で、ブラウザから http://server/svn_ajaxview/svnindex.xslhttp://server/svn_ajaxview/ajaxview/ajaxview.js にアクセスできるかを確認してみてください。
    アクセスできなければ、httpd.conf の Alias 設定などが正しいかを確認してください。
  3. httpd.conf 内の Location ブロック内に SVNIndexXSLT /svn_ajaxview/svnindex.xsl を追記してください。
  4. その後、Apache を再起動してください。

技術的な話

以上はどうでもよい話で、これからが書きたかったことです。
長くなりますが、覚え書きのために書いておきます。

目的

このプログラムを書いた目的は以下の通りです。

  • JavaScript について勉強する。
  • jQuery を使ってみたい。
  • pushState を使ってみたい。

そのため、 Subversion をブラウザ上で綺麗に表示することが目的ではありません。
そういうことであれば、WebSVN などを使うとよいと思います。(PHP を入っていなければ面倒ですが。)

Subversion と WebDAV

Subversion リポジトリを Apache 経由で公開する場合、通常は WebDAV という技術を用いて、つまり WebDAV プロトコルを用いてサーバーとクライアント間でやりとりが行われます。

WebDAV とは HTTP を拡張したプロトコルで、通常の HTTP 1.1 で定義されたメソッドに加え、いくつかのメソッドが定義されています。
HTTP 1.1 では、よく使われる GET, POST 以外にも OPTIONS などのメソッドが RFC では定義されていますが、WebDAV ではその他にも PROPFIND などが定義されています。

Subversion のサーバーとクライアントでは、これらのメソッドを用いて通信が行われています。

XMLHttpRequest で使えるメソッド

Ajax の中核となっているオブジェクトとして、 XMLHttpRequest があります。
これは、 JavaScript 経由でサーバーと通信できるようにするための仕組みです。

この XMLHttpRequest は、 WebDAV のメソッドも発行できるようになっています
Internet Explorer は知りませんが、少なくとも Firefox, Chrome, Safari では可能です。
確かに W3C の open メソッドの説明HTTP 1.1 の RFC を見る限りでは、 extension-method として他のメソッドを受け付けるようになっています。

ということは、 Subversion クライアントが WebDAV 通信をしている以上、 Subversion クライアントが行えることは、すべて Ajax で行えることになります。
(もちろん、ローカルストレージが必要なチェックアウトなどは別です。)

と思ったので、既に存在するかどうかは別にして、「pure JavaScript で Subversion クライアントを作ってみたい」というのがそもそもの動機でした。

今回はビューワを作りましたが、意味があるかは別として、その気になればコミットも可能だろうと思います。

pushState

せっかく Ajax を活用してみたので、 pushState を活用して、 URL も動的に追従するようにさせてみました。

その他

  • Chrome では XML の解析時に getElementsByTagName で名前空間を無視して要素を参照できるようですが、 Firefox ではきちんと getElementsByTagNameNS で名前空間を指定しないと無理でした。
  • あまりきちんとエラー処理していません。
  • Subversion の通信の手順の詳細な仕様がよく分からなかったので、Subversion のソースと Wireshark のパケット解析に基づいて実装しました。
    なので、何かおかしな挙動があるかもしれません。
  • もともとは Chrome の拡張機能として作成していました。
    いずれこちらも整理して公開するかもしれません。
  • Subversion リポジトリにブラウザからアクセスしたときの見た目を変更する方法は、 Subversion Book の "Customizing the look" に載っていました。
  • バグがありましたら、教えていただけると嬉しいです。(対応できるかは未定です。)

というわけで、あまり役には立たないような気もしますが、せっかく作ったので公開してみました。

2012年4月15日日曜日

Ruby の Garbage Collection に関するメモ

Exerb でのバグ報告に関連して、Ruby の Garbage Collection について調べていたときのメモです。

Ruby の EXE 化

Ruby 勉強会の準備をしていて、「Windows 上での Ruby の EXE 化」についてまとめていました。
私は Ruby 1.9.3 では Ocra を使っていますが、Ruby 1.8.7 の頃は Exerb を使っていました。

どちらもとてもよいツールでお世話になっていますが、どちらかというとレシピファイルで同梱ファイルを指定できる Exerb の方が好きです。
ただし、Exerb は Ruby 1.9 には対応していません。
もともとの作者の Yuya さんは、今は開発に関わっていないらしく、このまま 1.9 系列の開発はされないのかもしれません。
ちょっと残念です。

Exerb で報告されていた挙動

2月ぐらいに、Integer#to_s でごくまれに変な文字列になるという報告がされていました。
で、今回、勉強会の資料を作るついでに気になったので (というか、重大なバグがツールに含まれていると勉強会でおすすめしづらいので) 調べてみました。

たとえば、以下のようなソースで、ごくまれに変な文字列が表示されます。

原因

原因を調べるために、何ヶ月かぶりに Windows を立ち上げて調べてみました。

原因は、Bignum クラスのメソッド to_s 内で、テンポラリに作られた Bignum オブジェクトが、意図せず Garbage Collection で解放されてしまうためでした。

なお、これは Ruby 1.8.7 での話です。Ruby 1.9 では、このあたりがもう少し高速なアルゴリズムも併用するように変わった関係で、発生しません。

bignum.crb_big2str0 関数に以下のようなところがあります。

ここでは、(1) で変換元の値 x をコピーして、その中の実際に数値を保持している配列のアドレスを (2) でポインタ ds に取り出しています。
その後、戻り値用の文字列オブジェクトを (3) で用意し、これ以降で変換した後の文字列を生成しています。

障害が発生する場合は、(1) で生成したオブジェクトが (3) で解放されてしまっていました。
その結果、(3) 以降で t の中身である ds を参照しても、変な値しか残っていない状態になっていました。

Ruby の Garbage Collection

Ruby のスクリプトの中で new されたオブジェクトならともかく、C言語で書かれた Ruby ライブラリや、Ruby 自体のソースコードの中で生成されたオブジェクト (今回の t のようなもの) が、どうやって自動で解放されているのか、ずっと不思議でした。
オブジェクトの一覧は簡単に取得できるはずですが、どれを解放の対象とするかどうかの判断が難しいのではないかと思っていました。

WEB 上で資料を探してみると、少し古いですがRuby ソースコード完全解説の中で詳しく解説されていました。

こちらを読みながら、実際に現在のソースコードを見ていると、C言語ライブラリなどで生成されたオブジェクトは、スタック上に Ruby オブジェクトらしきものを探し、発見されればそれは Garbage Collection の対象としないという仕組みになっているようでした。

率直な感想としては、「そんな適当に判断して大丈夫なの」というものでしたが、Garbage Collection は、解放可能なものをすべて解放する必要はなく、解放すべきでないものを解放してしまわなければよいものなので、これでもうまくいくようです。

ちなみに、今回の障害は、上記ソースコードの tds が運悪くスタック上の同じ番地にとられてしまうと発生していました。
Exerb のコンパイルオプションだと、偶然そうなっていたようです。
その結果、(3) の時点では既にスタック上からは t そのものは消えており、Garbage Collection による解放の対象となってしまっていました。

修正

よって、ds を参照している間は、t もスタック上に残っているようにすれば、間違って解放されることもなくなります。

Ruby のソースコードでは、このためのマクロがあり、RB_GC_GUARD が定義されています。

これを使い、RB_GC_GUARD(t);ds を最後に参照している箇所より後に書けば、うまくいくようになります。

マクロ RB_GC_GUARD は、volatile 修飾子を使って、引数である t を強制的にその場で参照するようにするものです。
その結果、tds と同じメモリ番地に割り当てられるようなこともなくなり、きちんと t がスタック上に残るようになります。

というわけで、念の為に Ruby 本家の方も直してもらおうとチケットを書きかけましたが、Exerb のメーリングリストを見ておられたのか、Ruby コミッタの nobu さんが既に修正されていました。

nobu さん、ありがとうございます。
そして、Ruby 1.8.7 の ChangeLog に私の名前も入ることになりました。わーい。

2012年4月9日月曜日

YouTube に動画をアップロードしてみました

YouTube に動画をアップロードしてみました

長い間、記事を書いていなかったので、内容はないですが、 YouTube に初めて動画をアップロードしてみたので載せます。

動画の説明

Subversion

Git, Mercurial など、分散型のバージョン管理システムがはやってきていますが、習得の容易さや、切り替えのコストなどの理由から、特に会社などでは Subversion もまだまだ使われているようです。

Subversion は、 Apache が開発していることもあり、標準で Apache 経由での HTTP によるリポジトリの公開ができます。

ブラウザでのリポジトリの表示

ブラウザで、 Subversion のリポジトリにアクセスすると、最新のリビジョンの内容を表示させることができます。 また、 p=1234 のようなオプションを URL に付けると、任意のリビジョンを指定して表示させることもできます。

しかし、ログや変更日時、作者やファイルサイズなどは、標準では表示されません。

私としては、ログを表示できないのはかなり不満です。

そういうわけで、 TortoiseSVN のリポジトリビューのようなものを、ブラウザ内で実現してみました。

こちらは、そのサンプル動画です。

暇があればきちんと書いて公開し、説明を書こうと思います。

2012年2月9日木曜日

tinyURL で、長い data スキームを処理させる

tinyURL で、長い data スキームを処理させる

忘れたらググればいい に書いてあったことを見て、こんなのを考えてみました。

原理上は、どのような長さの data スキームであっても、 tinyURL で短い URL に変換できるはずです (対応ブラウザなどは調べていません)。

こういうことを tinyURL がよいと思っているかどうか不明なので、 GitHub などには置きません。
自己責任でどうぞ。

長い data スキームであっても tinyURL で処理可能にするスクリプト

できること

原理上、どれだけ長くても tinyURL で data スキームへリダイレクトさせることができます。

例えば、前に作ってみた iPhone Safari 上で動くテトリスでは、 http://tinyurl.com/7zsxzglのようになります。

このリンクをクリックすると、 Loading... と出た後、 data スキームで記述されたテトリスの画面になります。

本題とは関係ないですが、このテトリスは、枠内を、フリック・タップすることで、移動・回転です。

手順

あらかじめ、任意の長さの data スキームに変換済みの HTML ページを用意し、以下のようなコマンドで、 URL が生成されます。

なお、 Ruby スクリプト test.rb は、記事の末尾につけておきます。

原理

概要としては、だいたい以下のようになります。

  • data スキームを短い断片に分割し、それぞれを tinyURL で短縮 URL にしておきます。
  • トップページとなる Loading 用のページを用意します。最終的に、このトップページを data スキーム化し、 tinyURL で短縮 URL にしたものにユーザーはアクセスします。
    このトップページでは、以下のようなことを行います。
    • JSONP を用いることで、動的に、分割した断片の data スキーム文字列を集めて結合します。
    • すべての文字列が結合されたら、 location.replace で、生成された data スキームにジャンプします。

実際には、リンクリストになるように、少し工夫した断片 tinyURL を生成したりしていますが、原理は以上のようなものです。

スクリプトでは、対象となる data スキームファイルを用意するだけで、上記をすべて自動で行ってくれます。

というような方法で、あらかじめ tinyURL を生成しておけば、 Twitter などでも容易に長いデータや画像などのやりとりができると思います。

なお、繰り返しておきますが、 tinyURL 側が、これを良いと思っているのかどうかは分かりませんし、私も推奨しているわけではありません。
あくまで、技術的にはこういったことができる、ということだとご理解ください。

なお、ターゲットとなる data スキームファイルは、以下のように、 data: なども付与した状態で作成しておいてください。

data:text/html;base64,PD94bWwgd...

以下にスクリプト test.rb 全文を載せます。 Ruby 1.8, 1.9 で動くはずです。

適当に作ったので、バグなどあるかもしれませんが、ご了承ください。

なお、このスクリプトは、プロキシ下の環境ではうまく動かないかもしれません。
get_tiny_url の中をプロキシ対応にするのと、12行目の length を短めにすると、うまく動作すると思います。

2012年2月2日木曜日

Mozilla Vision 2012 Conference Day

Mozilla Vision 2012 Conference Day

忙しくてブログを書く暇がとれませんでしたが、少し前の Mozilla Vision 2012 Conference Day について書こうと思います。

この Conference は、「Web テクノロジーからアート、教育まで、オープンを考える」という主題のもとに開かれたもので、私は以下のセッションに出ました。

  • モバイル業界に真のオープンを!
  • Web 標準の今、そして未来
  • pdf.js - HTML5 と JavaScript の限界に挑戦する

以下では、出席したセッションを中心に、適当な雑感を書こうと思います。なお、英語が聞きとれない箇所もあったので、いつにも増して不正確な内容が多いかもしれません。

モバイル業界に真のオープンを!

Boot2Gecko プロジェクトの話でした。

簡単に書くと、 Android の基盤を利用し、真にオープンな Mobile プラットフォーム (スマートフォン) を構築する、ということが目的のようです。
Chrome OS のスマートフォン版という印象を受けました。

Mozilla としては、 PC の環境では Web ブラウザ上で非常にリッチな体験が可能になっており、それが OS を問わずに可能になっているが、スマートフォンの分野では Android, iOS, Windows Phone など、各社の独自規格が乱立しており、仕様としてオープンなものが中心になっていない、と考えているようです。

そこで Mozilla の解としては、 HTML5 を中心としたテクノロジでスマートフォンを動作させることを目指しているようです。

個人的には、近い将来に実現するのは難しい印象を受けました。

PC の場合、連綿と続いてきた x86 アーキテクチャや、 ACPI という OS とファームウェアのインターフェース、 UEFI といった具合に (オープンかは別として) デファクトスタンダードな仕様が固まっています。

だから Linux のようなものを簡単にインストールできるわけであり、 Chrome OS も作ることが可能なのだろうと思います。

一方で、 Android の方に関しては、ハードウェアやファームウェアの仕様は今後まだまだ流動的な状態が続くのではないだろうかと思います。
そのため、 Mozilla が独自に各社からどんどん出てくる Android 機種に対して、対応する Boot2Gecko を開発するのは難しいのではないかと感じました。
少なくとも、近い将来に「スマートフォンの OS を手軽に入れかえる」ということが一般的になることはないと思いました。

また、私の隣りの人がとても流暢な英語で質問していましたが、結局 HTML5 上ですべてのアプリを動かそうとすると、 Android や iOS のように、 Native に近い環境でアプリを動かすのに比べ、どうしても動作速度の面で劣るのではないかという懸念があります。

これらのことから考えると、私としてはすぐに一般的になることはないように感じました。

Web 標準の今、そして未来

こちらは、「オープンな仕様を目指して」といった内容でした。

CSS の策定などにも関わってきた発表者の方が、「オープンな仕様がいかに大事か」や「オープンなプロセスを保つためにはどのようにするべきか」などについて、熱く話していました。

個人的には、 HTML, CSS の歴史の裏話は面白かったのですが、発表者と自分自身の温度差が大きかったです。

pdf.js - HTML5 と JavaScript の限界に挑戦する

こちらは、 JavaScript で PDF を表示するという挑戦でした。

技術寄りの話だったこともあり、非常に面白い内容でした。

冒頭は、お決まりの「PDF のプラグインは closed だからよくない」ということからスタートでした。

ただ、技術やユーザー視点でのメリットとしては、「JavaScript で提供することで、 PC, Mobile のいずれでも使える」や「ブラウザの挙動 (戻る/進む など) と、一貫性のある動作を提供できる」などがありました。

技術的には以下のような方法で取り組んだそうです。

基本的な描画

canvas で描画する。 SVG は用いない。

画像/文字の描画

PDF は、ブラウザがサポートしていない画像形式やフォント形式をサポートしている。

画像に関しては、 JavaScript でデータを解析し、 canvas に描画している。
フォントに関しては、ブラウザ未対応な形式のフォントデータを、ブラウザが対応している OpenType に変換することで、対応した。
このフォント部分の解決がなければ、プロジェクトは頓挫していたらしい。

リンク機能

リンク機能に関しては、ブラウザの「戻る」、「進む」と完全に連携しており、プラグインよりもずっと使いやすくなったとのことだった。

テキスト選択

canvas に画像として描画しているので、テキストを選択することができない。
これを解消するために、 canvas の上に、透明な色で別途文字を通常のテキストとして配置することにしたらしい。
この文字自体は、フォントなどはそれほど考慮されていないもので、あくまでテキスト選択ができるようにするためのものらしい。

このあたりまでくると、「そこまで頑張らなくても。。。」という気がしなくもない。

高速化

UI 以外は、極力 WebWorker を使って Core を分散することで高速化を実現したとのこと。

いずれも、技術的には面白かったのですが、少しやり過ぎな感がありました。


行く前は、 Google Developer Day のようなものを期待していたので、そういう意味では期待外れでした。

一方で、 Mozilla が「オープン」というものを、強烈に推進しようとしているという熱意は、異常なほどに強く感じました。WLAN のパスワードからして whatisopen でしたし。

そういう意味で、 Netscape という膨大な資産をつぎこんで作られたプログラムを公開するという、考えられないような決断をしたことからスタートした Mozilla という組織は、方向がぶれないまま進んでいるという印象を受けました。

2012年1月1日日曜日

NPAPI プラグインの作り方 for Windows その5

NPAPI プラグインの作り方 for Windows その5

今回は、サンプルの簡単な説明をします。

なお、今回でひとまず NPAPI プラグインの作り方は終了です。要望があればコメント欄に書いてください。気が向けば対応します。

これまでと同じく今回のサンプルは、GitHub のページからダウンロードできます。
この中の modified_files/npruntime/plugin.cpp が主に説明する対象です。

HTML ファイルからプラグインの呼び出し

テスト用の HTML ファイル test.html からプラグインを参照しているのは以下の箇所です。

embed タグはプラグインをロードするために使われるタグで、type 属性にプラグインの種類を指定することで、目的のプラグインをロードします。

type 属性には、プラグインの MIME type を指定します。
サンプルの場合は、application/mozilla-npruntime-scriptable-plugin になっています。

このプラグインの MIME type は、Windows の場合はリソースファイル nprt.rc 内で定義されています。

オリジナルのプラグインを作成する場合は、以下の MIMEType の箇所を好きなものに変更してください。
もちろん、変更した場合は test.htmlembed タグの方も同じ文字列に変更してください。

なお、MIME type の仕様としては、独自の種類を定義する際は application/x- で始まる文字列にすることが推奨されているようです。

複数の MIME type に対応する場合は、| で区切ればよいようです。

なお、HTML ファイルからの呼び出しには直接は関係ありませんが、ProductName でプラグインの名前を、FileDescription でプラグインの説明を記述するなどが決められています。

また余談ですが、Windows 向けの NPAPI ではこのようにリソースファイルで MIME type を指定しますが、Unix などでは、np_entry.cpp 内の NP_GetMIMEDescription 関数で返す文字列で MIME type を指定します。
逆に言えば、Windows 環境では NP_GetMIMEDescription で返される文字列の値は、ブラウザに参照されることはありません。

プラグイン内で使われる変数

NPVariant

NPAPI プラグインの中では、JavaScript 側とやりとりをする際に、NPVariant という型がよく出てきます。

この型は、npruntime.h 内で以下のように定義されています。

type フィールドには、現在 value に保持している値の種類が格納されており、value にその値が保持されます。

Windows の COM を扱う際に登場する VARIANT 型と同様なものだと考えればよいと思います。

NPVariant 型の変数に値を代入したり値を読み出したりする際は、BOOLEAN_TO_NPVARIANTNPVARIANT_TO_BOOLEAN マクロを使うとよいと思います。

変数の動的確保と解放

JavaScript 側とやりとりをする場合、特に文字列などをメソッドなどの戻り値として返す場合、その文字列の領域を動的にメモリ上に確保する必要があります。

通常の C 言語であれば、mallocfree などを呼び出しますが、NPAPI プラグインでは NPN_MemAllocNPN_MemFree を用いることになります。

ちなみに、前回の記事でサンプルの修正をしたのは以下の部分でした。

これは、本来であれば NPN_MemAlloc でメモリを確保すべきなのですが、_strdup で文字列用のメモリを確保してしまっていることが問題でした。

NPN_MemAlloc, NPN_MemFree などは、プラグインロード時にブラウザから関数ポインタとして渡されます。
そのため、プラグイン作成者側には、その内部でどのようにメモリが管理されているかを仮定することはできません。

そのため、NPN_MemAlloc 内部で malloc と同様のものを呼んでいるのであれば、サンプルを修正しなくても動作するかもしれませんが、そうでない場合は、ブラウザ側が戻り値の文字列を NPN_MemFree しようとしたタイミングでクラッシュすることになります。

プラグインのメソッドの呼び出し

ここでは、プラグインのメソッドの呼び出し方法と、新しいメソッドの追加方法について書きます。

プラグインのメソッドの呼び方

プラグインのメソッドを呼ぶには、以下のように embed 要素を取得し、その要素に対してメソッドを呼び出します。

プラグインのメソッドの定義

呼び出されるメソッドは、以下のように定義されます。

ここでは、実際にサンプルで定義されている foo メソッドについて説明します。

HasMethod の対応

まず、HasMethod 関数の対応をします。

この関数は、特定の名前のメソッドを持っているかどうかを判定するための関数です。

サンプル内では、下記のようになっている箇所です。

ここで、sFoo_id は、CPlugin::CPlugin で初期化されていますが、"foo" という文字列を表すものだと思ってください。

上の例では、sFoo_id が表す foo という名前か、sDiskSize_id が表す diskSize という名前の文字列なら true を返すことになります。

メソッドの実体の定義

メソッドの実体は、以下のような関数内で定義されています。

この Invoke 関数は、プラグインに対してメソッドが呼ばれたときに、メソッド名や引数の配列などとともに呼び出されます。

そこで、この関数の中で、メソッド名に応じて処理を分けてやることで、各メソッドの処理を実装することができます。

上の例では、もともと存在した foo メソッドに加え、新規に diskSize というメソッドを追加した場合です。

このように、いくらでも自由にメソッドを追加することができます。

もちろん、数が多くなればメソッド名とコールバックをハッシュに格納するなどして、効率化すべきでしょう。

プロパティの場合も、HasProperty, GetProperty, SetProperty 関数の内部で同様に実現されています。

ひとまずこれで簡単な NPAPI プラグインの作成方法の説明を終わります。
質問などがあれば、コメント欄までお願いします。