自分好みのガジェットを作る! Windowsサイドバーガジェット作り入門

第6回ガジェットのAPI、セキュリティ、ActiveXの組込みなど

ガジェットのAPI

Windowsサイドバーガジェット用に用意されている拡張APIについて、このようなものがあるというのを簡単に紹介していきます。詳しくはWindows SDKまたはMSDN Online Libraryを参照してください。

スキーム

gImage スキーム

gImageスキームはhttpやfileスキームと同じように指定して、ファイルのサムネイルや画像をリサイズした上で読み込むためのスキームです。

例えば、ファイルのサムネイルを得る場合に利用できます。使い方は以下のような感じです。

<img src="foobar.png" /> <!-- 通常通り -->
<img src="gImage:///foobar.png" />
<img src="gImage:///foobar.png?width=100&height=100" />

オブジェクト

System.Environment (環境)

環境変数の取得のためのメソッド、コンピュータの名前を取得するプロパティが提供されています。

System.Gadget.SideShow (Windows SideShow)

Windows SideShow用のAPIを持っています。SlideShowではありません。SideShowとはノートコンピュータの液晶裏についたサブディスプレイなど情報補助表示装置です。その補助表示を操作するためのAPIが用意されています。

System.ContactManager (アドレス帳)

メールなどのアドレス帳の内容を持っています。

System.Machine (コンピュータ情報)

コンピュータそのものの情報、例えば、電源やCPU使用率、メモリ使用率などをもつオブジェクトをSystem.Machine.*に持っています。

System.MessageStore (メール)

メールボックスの状態などを得ることができるオブジェクトです。未読件数などを表示するのに利用できます。

System.Network.Wireless (無線LAN)

その名のとおり無線LANの接続状況についての情報を持っています。

System.Shell (ファイル・シェル操作)

ファイル操作を助けるためのAPIを持っています。例えば、ファイルの移動やドラッグアンドドロップで渡された情報からファイル情報を簡単に得るための仕組みなどを提供してくれます。

System.Sound (音をならす)

簡易的に音を鳴らすためのAPIを提供します。音楽を鳴らすというよりは効果音を鳴らすだけという用途向きです。もし音楽再生を求めているのであればWindows Media Playerを使うなどしてください。

System.Time (時刻)

現在の時刻とタイムゾーンの管理を行うオブジェクトです。

セキュリティ的に気をつける点

ガジェットはマイコンピュータゾーンかそれ以上に危険であると思うべき

つまりユーザに特に訪ねることなく、コンピュータに対して様々なことを事実上無制限に行えます。これは常に念頭に置いてください。

また、Internet Explorerのマイコンピュータゾーンの設定によらずActiveXの実行などが許可されるため、Internet Explorerよりも危険な状態にあるといえます。

不用意にevalしない

evalというのは知っての通り任意のJavaScriptを評価する関数です。

evalを使う場面はJSONを使う場合(以前のサンプルもそうでした)に多く見られると思いますが、もし出力形式にXMLやその他形式を選択できるのであれば避けることをお勧めします。

そもそもevalを利用して外部から得たスクリプトの文字列を評価するというのは、その得られた文字列が安全であるということを証明できない限り避けるべきです。

なぜならば先ほども述べたとおり、ガジェットはマイコンピュータゾーン相当で動作しているからです。つまり、悪意あるスクリプトを受け取りevalしてしまった場合やりたい放題になってしまいます。それこそ、ファイル操作やXMLHttpRequest、ActiveXObjectでCOM操作も何でも、です。

では、⁠文字列が安全であるかどうかを証明できるのか」というと、これもまた面倒な話です。悪意あるスクリプトが返される理由は経路上での改ざんやそもそも悪意あるサービスだった場合などがあげられますし、自分の信頼できるサーバでSSLを使ったとしても、そもそもサーバのデータが改ざんされていないことを証明しなければいけません。ということは電子署名のようなことを行えば何とかできそうです。という感じで一筋縄ではいかないのです。

もっともevalを必要とする場面というのは、いいところJSONをデシリアライズする点ぐらいしか考えられないので、JSONをやめることができないかどうかを考慮した方がよいでしょう。

エスケープのし忘れに気をつける

いわゆるXSS(クロスサイトスクリプティング)を防ぐという話です。

悪意ある入力を引き継いでガジェットを動作させることは一般的なWebアプリケーションよりは困難ですがあり得ないわけではないですし、外部から取得したHTMLが悪意あるものである可能性もあります。そのようなものを何も考えずinnerHTMLプロパティにセットするとeval同様大変なことが起こる可能性があります。

そもそもそういうセキュリティ面もそうですが、正しく表示できていない時点で不具合ですから受け取った表示するときにはHTMLをきちんとエスケープします。

また、HTMLをエスケープするよりもinnerTextプロパティを使うことができるかどうかを検討するのもよいと思います。innerTextプロパティはinnerHTMLプロパティと似たもので「要素の内容テキスト」を表すプロパティです。このプロパティはあくまで表示するテキストなのでエスケープしない状態でセットできるのです。下手にエスケープするより単純で間違いがありません(もちろんinnerHTMLとinnerTextを間違えたら悲惨ですが……)。

var html = "<p><!-foo -->bargao </p>";
element.innerText = html; // <p><!-foo -->bargao </p>
element.innerHTML = html; // bargao

ガジェットの中で外部ウェブサイトへ遷移しない

よくあるかどうかはわかりませんがガジェットの中でミニブラウザを!といった考えを持つ開発者の方がいらっしゃるかと思いますが、決してそのようなことは考えないでください。

これも推奨しない理由はガジェットからのローカルのリソースへのアクセスが無制限となっていることによります。

※当初、ガジェットはマイ コンピュータゾーンで動作している旨の説明となっていましたがガジェットはマイ コンピュータゾーンに属さず、Internet Explorerの設定にかかわらずActiveXの動作が許可されるとのご指摘をいただきました。お詫びして訂正させていただきます。

以下のような内容のHTMLであるページがhttp://www.example.com/test.htmlにあるとします。

<pre id="output">[Output]</pre>
<script>
    var fso = new ActiveXObject("Scripting.FileSystemObject");
    var tf = fso.OpenTextFile('C:\\Windows\\win.ini', 1, 0);
    document.getElementById('output').innerText = tf.ReadAll();
</script>

試しにこのページをInternet Explorerで開いてみると、情報バーが出てくるはずです。当然信頼できないサイトでActiveXObject(COM)を利用することを無断で許可することはありません。

そして次にこのHTMLをガジェットの中でiframe要素を使って読み込むようにして、ガジェットをサイドバーに追加します。すると何ごとも無かったかのようにガジェット中のiframeにwin.iniが表示されます。

これはインターネットにあるHTML(のスクリプト)がローカルコンピュータのデータを読み取ることができてしまったということです。これをpre要素ではなく何処か外部に投げるようにしたら怖いですよね。ガジェットの中でウェブページを開くとそのような危険な状態になってしまうということです。

ガジェットのリンクなどはクリックして遷移する必要がある場合には自動的に外部のウィンドウで開くようになっています。ですから、わざわざ遷移できるような仕組みを用意すると問題となります。

ActiveX(Flash、Silverlight等)を組み込む

ガジェットは以前何度か説明している通り、Internet Explorerベースです。ということはActiveXコントロールをホストすることができるということでもあります。

ActiveXコントロールをホストできるとどのような恩恵を受けることができるのでしょうか?

ActiveXコントロールのホストというと判りにくいですが、要するにHTMLのobject要素で埋め込む「アレ」です。よく目にするものとしてはAdobe Flash Playerやメディアプレイヤーなどがあります。ということはガジェット内でもFlashやメディアプレイヤーなどを普通のWebサイトと同様に利用できるということです。

Flash以外にもSliverlightも実際はobject要素で埋め込む形になるので、ガジェットをSilverlightで作ってしまうことも可能ということです。

埋め込み方はWebページで使うときと変わりないので説明は割愛します。

x64版Windowsでの制限

Windows Vistaには32bit版と64bit版(以下x64)という二つのプラットフォーム向けのものが用意されています。この違いが場合によっては問題を引き起こすことがあります。

通常32bitアプリケーションはx64のVista上でも、ほとんど変わりなく利用することができます。

さらにサイドバーガジェットは通常HTML+JavaScriptで構成されるので、プラットフォーム依存は何もなく、問題なく動くように思えます。

ところが一つ前に説明したActiveXのホストを行っている場合にうまく動かないことがあるという問題が発覚します。例えば現状でよく使いたくなるであろうAdobe Flash Playerは動きません。

原因は64bitのプロセスに32bitのライブラリをロードすることはできないという元々のWindowsの制限にあります(その逆の32bit上に64bitというパターンもありえます)。その制約を受けた上でサイドバー自体は64bitアプリケーションとして実行され、サイドバーが持つInternet Explorerも64bit版となります。

そのために32bit版のみ提供で64bit版には提供されていないFlash Playerなどを表示できなくなるのです。素の64bit版Internet ExplorerでFlashを表示できないのも同様の理由です

回避策

裏技的ですが32bit版のサイドバーを起動することでこの問題を回避できます。32bit版のサイドバーは以下のパスになります。

\Program Files(x86)\Windows Sidebar\sidebar.exe

32bit版のサイドバーを起動することで32bit版のActiveXなどをホストできるようになりますが、32bit版を起動し直すことをユーザに指示する必要があるなど根本的な解決にはならないのでオススメはできません。

メモリリーク

Internet Explorerでは特定のパターンでメモリがリークしてしまうことがあるということが、広く知られています。そしてInternet Explorerで起こることはWindows サイドバーでも起こること。

このメモリリークパターンについてはInternet Explorer リーク パターンを理解して解決するが参考になるので、一度目を通しておくとよいと思います。

JavaScript以外のスクリプト言語を使う

実はということもありませんが、サイドバーガジェットで使える言語はJavaScript(Microsoftの実装をJscriptという)のみということもありません。

アクティブスクリプトと呼ばれる仕組みを使っているので、そのアクティブスクリプト対応エンジンがあれば大体使えます。Windows標準で使えるアクティブスクリプトにはJScript以外にVBScriptがあります。

他にも各種スクリプトエンジンをインストールすればJScriptとVBScript以外の言語を利用できるようになります。 Rubyを使いたいならActiveScriptRubyPerlを使いたいならActivePerlをインストールして、script要素のlanguage属性で言語を指定することで利用できます。例えば以下のような半分Perl,半分Jscriptという組み合わせも動きます。

<script language="PerlScript">
use LWP::Simple;
</script>
<script type="text/javascript">
document.getElementById('output').innerText = get("http://www.google.com");
</script>

これはPerlのLWP::Simpleというモジュールのget関数をJScriptから呼んでいる例です(get関数はLWP::Simpleをuseすると公開される)。ちなみにこのLWP::Simpleのget関数というのはHTTPのリクエストを投げてレスポンス内容を返すという単純な関数です。

このようにアクティブスクリプトでは異なるスクリプト言語を混ぜて使うことができるところがとても面白いです。面白く便利ではあるものの、JScriptとVBScript以外はWindowsに標準で入っていないのでガジェットの導入の敷居が一気に上がってしまうのが難点です。逆にそれらが入っている前提でよいのであればいろいろと面白いことができるかもしれません。

alert的なメッセージボックスを利用したい

前回alert関数はガジェット上では利用できないというお話をちょこっとだけしたのですが、やはり使えないというのでは「~してもよいですか?」という画面を作ったりするのは面倒です。

そこでalertのようなものを何とかして使う方法を考えるわけですが、何か良い方法は無いものでしょうか。

というところで気がついたのですがalertはInternet Explorerが用意しているものですが、VBScriptにはalertそっくりなメッセージボックスを出す関数MsgBoxがVisual Basic由来で「言語仕様」にあります。つまりalert関数と違ってVBScriptを使える限り呼べるのです。

ということはこのMsgBox関数をJScript側から呼び出せればうまくいきそうな気がしてきました。JscriptとVBScript異なる言語が混じっても利用できるというのは前に説明済みのとおりです。

ただし、VBScript組み込みの関数をいきなりJScript側から呼ぶことはできないのでVBScript側で公開用の関数を作成する必要があります。

ということでそのあたりを面倒見て、メッセージボックスを呼び出しやすくするためラッパーライブラリを作成しました。

このライブラリの使い方は簡単でまず以下のように読み込みます。

<script type="text/javascript" src=" messageBoxBridge.js"></script>

そして、メッセージボックスを呼び出したいタイミングで以下のようなコードを書きます。

MessageBox.show("テスト");

これを実行すると図のようなメッセージボックスが表示されます。

画像

このライブラリは.NET Frameworkの System.Windows.FormsネームスペースのMessageBox.Show メソッドをまねています。

このライブラリでのメソッドは一つ目の引数が内容、二つ目がウィンドウタイトル(省略時document.title)、三つ目がボタンとアイコンを受け取ります。ですのでalert以外にもconfirmに相当することもできます。

if (MessageBox.show("なになにしてもよいですか?",
                    "Sample Gadget",
                    MessageBoxButtons.OKCancel | MessageBoxButtons.Question) == DialogResult.OK) {
  MessageBox.show("OKが押されました");
} 

このコードは次の図のメッセージボックスを表示し、OKボタンを押すと「OKが押されました」というダイアログが表示されます。

画像

これでalertやconfirmが無くても同等のことを実現できるようになりました。

最後に

ガジェットの作り方の連載は今回で最後になります。ちょっとしたHTMLとJavaScriptの知識で作れるので是非作ってみてはいかがでしょうか?

この連載がお読みいただいた方々の開発時に何らかの形でお役に立てることを願ってやみません。

おすすめ記事

記事・ニュース一覧