イベントのスクリプティング
Andrew Clinick
Microsoft Corporation
April 9, 2001 日本語版最終更新日 2001 年 6 月 5 日
この記事は、もともと MSDN Online Voices のコラム "Scripting Clinic" に掲載されたものです。
このコラムのサンプル コードのダウンロード
イベントのスクリプトを作成することは、非常に簡単なことです。マイクロソフトやサード
パーティからの多くのアプリケーションを使用して、アプリケーションが提供するオブジェクトか
ら発生するイベントに応答するスクリプト コードを記述できます。アプリケーションはイベント
を通じて適切な時点で呼び出しを行い、イベント ハンドラのコードを記述することにより、
その呼び出しに応答することだけを理解しておけばよいので、これは開発者にとってスクリ
プトを作成する場合の優れた方法です。少なくとも理論上はこのとおりです。しかし実際
には、イベントはアプリケーションによって数多くの方法で処理され、実装されています。
したがって、イベントのスクリプトを作成する最適な方法は何かということに関して、すぐに
混乱を生じてしまいます。
私は、この機会にこういった混乱を整理するために、一般的に評判のよいアプリケー
ション、特に Internet Explorer、Windows® Script Host、および Windows®
Script Components でイベント処理スクリプトを記述するためのさまざまな選択肢を調
査してみようと考えました。
スクリプト エンジンがイベントを処理する方法
各アプリケーションでイベントを処理する方法を詳しく調査する前に、スクリプト エンジ
ン (アプリケーション内で実際にスクリプト コードを実行するコンポーネント) がイベントを処
理する方法を見てみましょう。アプリケーションの作成者がイベント処理を有効にするメカ
ニズムは本質的に 2 通りあります。1 つは組み込みまたは "automagic"(自動的な) サ
ポートで、もう 1 つは関数またはサブルーチンを呼び出すメカニズムです。
"Automagic" (自動的な) サポート
JScript® と Visual Basic® Scripting Edition の両方の Microsoft®
Windows® スクリプト エンジンは、名前付け規則を使ってイベントのスクリプトを結び
付ける組み込みのメカニズムを提供します。読者が VBScript のプログラマであれば、おそらく
Visual Basic® および VBScript のイベント ハンドラに対する Object_Eventname
という名前付け規則に既に馴染みがあるでしょう。アプリケーションがスクリプト エンジンにオ
ブジェクトを提供し、スクリプト エンジンを Connected モードにすると、イベントが発生するた
びに正しい名前付け規則を持つサブルーチンが呼び出されます。たとえば、スクリプトが "order"
という名前のオブジェクトを持ち、そのオブジェクトが "onNew" というイベントを持つ場合、
そのサブルーチンは order_onNew() になります。"automagic" による結
び付けが機能するには、スクリプトがコンパイルされるときに、スクリプト エンジンがそのオブジェ
クトを使用できる必要があります。
おそらく、VBScript プログラマにとっては耳新しいことではないでしょう。しかし、私たちは
JScript がなぜこのメカニズムをサポートしないのですか、という質問をよく受けます。 JScript
は組み込みのイベント バインディング名前付け規則をサポートします。ただし、残念ながらあ
まりよく知られてはいません。私たちが JScript 3 を作り上げる際に、JScript にこのメカニ
ズムを追加する最善の方法は何かということについて、スクリプト チーム内で相当の議論が
交わされました。VBScript の表記法に従うべきか,それとも何か新しいことを行うべきか。私
は Object_Eventname という規則が実際のところ JScript の精神にはそぐわない
と感じていました。さらに、この名前付け規則を使用しているコードが既に存在している可能
性があることも認識しました。したがって、バージョン 3 にこれを追加することは、重大な互換
性の問題を引き起こします。
JScript は C に似た言語であると言われているので (Jscript は Java とはまったく似て
いない言語です。これは、JScript でのイベントの処理方法の次によく受けるもっとも共通し
た質問です)、名前付け規則として提案された代案は Object:: Eventname でし
た。order オブジェクトの例を再度使うと、onNew イベントの JScript イ
ベント ハンドラは order::onNew になります。これを説明するために、私
は Visual Basic と Windows Script Control を使って簡単なスクリプト ホストを作成したの
で、イベント ハンドラを試してみることができます。このプログラムは、3 つのイベント
onNew、onSave、および onDelete
を持つ order オブジェクトと、スクリプト コードを記述できる簡単なテキスト エディタを提供し
ます。

図 1. 実行中の Event Test Bed アプリケーション
関数/サブルーチンの呼び出し
アプリケーションがスクリプト エンジンをホストする (ホストの例には Internet Explorer、
IIS、および Windows Script Host などがあります) ときは、常にそのアプリケーションはスク
リプト コードで記述されたすべての関数またはサブルーチンにアクセスできます。ホスト アプ
リケーションは関数を参照できるだけでなく、その関数を呼び出すことができます。アプリケー
ションはこのコードを直接呼び出せる能力を使って、スクリプト エンジンへのイベント バイン
ディングを供給する別のメカニズムを提供します。ホスト アプリケーションは、イベントに応答
する組み込みの機能を使用するのではなく、オブジェクトが起動した任意のイベントを処理
するために、適切なスクリプト関数を呼び出すことができます。ホスト アプリケーションは、こ
のメカニズムを使って、イベント ハンドラに対して別の構文を定義できます。これは優れた
機能ですが、スクリプトでイベントに応答する方法に混乱を生じる結果になります。ホスト
アプリケーションは、さまざまな名前付け規則やコーディング技法を使用できます。たとえば、
order オブジェクトの例ではアプリケーション内に実装される onNew
イベントのイベント ハンドラを持つことができ、その上スクリプト内から orderOnNew
関数として呼び出すこともできます。
Internet Explorer のイベント
Internet Explorer は、非常に多くの異なる方法でイベントを処理するので、イベント
ドリブン スクリプトに関する混乱の主な根源になっています。ここで明らかな疑問は、Internet
Explorer は同じ結果を得るためになぜそんなに多くの方法を必要としているのかということ
です。その主な理由は HTML のイベントが本当の意味で標準化されていないことにあり
ます。そのため、IE は どのイベントを HTML に結びつけるかということと、ActiveX®
コントロールなどのほかのブラウザがサポートしない機能を処理するために、多くの方法を
サポートする必要があります。この結果、今日起こり得るほぼすべてのコンテキストを IE
で実行できるのでエンド ユーザーにとってはすばらしいことですが、スクリプトの作成者の
作業をより複雑なものにしています。
インライン スクリプト ハンドラ
インライン スクリプト ハンドラは、IE と Netscape の両方でサポートされているので、
IE のイベント処理ではおそらくもっとも広範に使用されているメカニズムです。基本的な
原則は、HTML 要素の内部にスクリプトを追加することで、ブラウザがすべての結
び付けを行います。以下に例を示します。
<span id="testinline" onclick='alert("inline handler - JScript")'>Click me inline - JScript</span>
ユーザーが span 要素に囲まれているテキストをクリックすると、onclick
属性に指定されたコードが呼び出されます。このメカニズムは少量のコードの場合は優れ
ていますが、多くのスクリプトを記述する必要がある場合は、扱いにくいものになります。
このイベント メカニズムは VBScript と JScript の両方で機能します。
ここで実際に行われていることは、Internet Explorer がそのスクリプト コードを指定し
てスクリプト エンジンを呼び出し、エンジンに匿名関数 (名前のない関数) を作成するよう
に指示します。VBScript は匿名関数をサポートしないので、VBScript の知識のある読
者はどのようにこれを行っているかおそらく不思議に思うことでしょう。実際には、VBScript
はそのスクリプトを含む "anonymous" という名前のサブルーチンを作成し、その後イベント
に結び付けられる関数へのポインタを返します。
関数ポインタ
JScript のあらゆる関数は最上級のオブジェクトです。JScript では関数をポインタとし
て渡すことができ、そのポインタを使用して関数を呼び出すことができます。これは、イベント
ハンドラの結び付けに柔軟性をもたらし、1 つ以上のイベントを処理するために同じ関数を
使用することを可能にしています。関数ポインタ イベントをセットアップするには、オブジェクト
の EventName プロパティに関数のポインタを設定するだけです。JScript ではこ
れを以下のように非常に簡単に行えます。
window.onclick=foo
function foo()
{
alert('you clicked on the window')
}
VBScript の最初のリリースでは、window.onclick に foo
を設定すると、VBScript はポインタを受け取るのではなく foo を呼び出す
ので、関数ポインタを使用する方法はありませんでした。VBScript 5.0 では GetRef
メソッドが導入されました。これは関数への参照を作成するので、以下のようにイベント ハンドラ
を設定できます。
set window.onclick=GetRef("foo")
function foo()
alert('you clicked on the window')
end function
<Script> ブロック - イベント ハンドラ
ここまで使用してきたイベント ハンドラは、HTML イベントに対しては適切に機能しますが、
ページ上の ActiveX オブジェクトのカスタム イベントのイベント ハンドラを記述する方法は提供
しません。このサポートを提供するために、Internet Explorer は <script> ブロックに対する
拡張を導入し、以下のようにスクリプトがどのオブジェクトの、どのイベントに対するものかを指定
できるようにしました。
<span id="testscript">Click me script block handler - JScript</span>
<script language=JScript for=testscript event="onclick">
alert("script block handler - JScript")
</script>
<br>
名前付け規則
最後に、Internet Explorer 固有のイベント結び付けメカニズムは、オブジェクト名とイベント名
を含む関数の命名法で成り立ちます。関数名が objectname.eventname の
形式の場合、IE は以下のように自動的に関数とイベントの結び付けを行います。
<span id="testnaming">Click me naming - JScript</span>
<script language=JScript>
function testnaming.onclick()
{
alert("script naming - JScript")
}
</script>
注意: このメカニズムは JScript だけで機能します。
Automagic
すべての IE 固有のイベント処理メカニズム以外に、スクリプト エンジンが提供する組み込みの
"automagic" (自動的な) 結び付けも使用できます。このメカニズムを使用する場合に重要なこと
は、この結び付けがいつ行われるかを理解することです。ページが読み込まれるときにオブジェクトま
たは HTML 要素が使用できる場合、スクリプト エンジンはイベント バインディングを行います。
ただし、(たとえば innerHTML を設定することによって) ページが読み込まれた
後にオブジェクトまたは要素が追加されると、スクリプト エンジンはイベントの結び付けを行いま
せん。このメカニズムが優れている点は、ActiveX コントロール イベントに応答するために使用できる
ことです。
<span id="testscriptbuiltin">Click me Built In - JScript</span>
<script language=JScript>
function testscriptbuiltin::onclick()
{
alert("script naming - JScript")
}
</script>
<br>
<span id="testscriptbuiltin">Click me Built In - VBScript</span>
<script language=VBScript>
sub testscriptbuiltin_onclick()
alert("script naming - VBScript")
end sub
</script>
これらのイベント ハンドラの実行例を表示します。
WSH のイベント
Windows Script Host のイベント結び付けメカニズムは Internet Explorer よりもはるかに単純で、
イベントを結び付ける方法を 2 つだけ提供します (2 つは 5 つよりもよいことだとは思いませんか !)。
とはいえ、WSH でイベントを処理するコードを記述することはちょっとした難問で、イベントが発生すると
きにスクリプトが依然として実行中であることを保証することすら簡単なことではありません。WSH スクリ
プトはスクリプトの最終行を実行した直後に終了するので、このことが問題になります。処理したいと思っ
ているイベントが発生する前に終了してしまう可能性もあります。この問題を扱うために、
WScript.Sleep メソッド (詳細については、http://www.microsoft.com/japan/msdn/library/ja/script56/html/wsMthSleep.asp
を参照してください) を使用して、長時間休止するループを作成することをお勧めします。イベントが発生
した後は、WScript.Quit メソッドを使用してスクリプトを終了します。 (私たちはこれを行うこと
が面倒であることがわかっています。したがって、 これを解決することが WSH 5.6 の次のバージョンでの
機能強化のリストに含まれています。) 確実にイベント ハンドラが呼び出される方法を実現した後は、
2 つのイベント処理メカニズムのどちらを使用するかを決定する必要があります。
WSH は、"automagic" と名前付け規則の両方のイベント結び付けをサポートします。WSH 1.0
で導入された名前付け規則システムは、WScript.Createobject を使用して作成されたオ
ブジェクトからのイベントに応答する方法を提供します。WSH 1.0 の頃は、WSH で外部オブジェクトを
作成する方法がなかったので、このメカニズムが必要でした。WScript.CreateObject は
VBScript CreateObject と似ていますが、イベント ハンドラ関数の名前付け規則を定義す
る 2 番目の引数が追加されています。以下に例を示します。
Set myobject = WScript.CreateObject("someobjectwithevents","myobject_")
この場合、WSH は Someobjectwithevents オブジェクトのインスタンスを作成し、イベン
トが発生するときに myobject_ で始まり、イベント名で終わる任意の関数が呼び
出されます。WSH は、内部的にイベントを処理し、スクリプト エンジンの名前付け規則に一致する関
数を呼び出すことにより、これを達成しています。"automagic" イベント結び付け構文は
object_eventname なので、一般的に VBScript ではこのことによる大きな影響は
ありません。しかし、JScript では object::eventname が機能しないので、状況は
やや異なります。以下に、CreateObject イベント バインディングの例を示します。
set myorder2 = WScript.CreateObject("ordersystem.clsorder","myorder2_")
myorder2.neworder(1)
sub myorder2_onNew()
Wscript.echo "new order received from myorder2"
end sub
Windows Script チームは、WScript.CreateObject メカニズムが混乱を引き起こしたこと
を認識していたので、WSH 2.0 では .wsf ファイルに <object> 要素を導入
しました。<object> 要素は、1 つの例外を除けば HTML の
<object> 要素とほぼ同じです。<object> 要素で定義されるオブジェクトが起動するイベントは、既定ではファイル内のスクリプト コードに結び付けら
れません。イベントの結び付けを有効にするには、以下のように <object> 要素の Events 属性を True に設定する必要があります。
<job>
<object progid="ordersystem.clsorder" id="myorder" events="true"/>
<script language="vbscript">
sub myorder_onNew()
Wscript.echo "new order received myorder"
end sub
myorder.neworder(1)
wscript.sleep 5000
</script>
</job>
WSH には、スクリプトが読み込まれた "後" に作成されたオブジェクトのイベントに結び付ける最終的
な機能が含まれています。これは、VBScript の CreateObject または JScript の新しい
ActiveXObject を使って作成されるオブジェクトで役に立ちます。既に作成されているオブジェク
トのイベントへの結び付けおよび結び付け解除のために、WScript の ConnectObject メソッド、
WScript.ConnectObject があります。
set myorder3 = createobject("ordersystem.clsorder")
wscript.connectobject myorder3,"myorder3_"
myorder3.neworder(1)
sub myorder3_onNew()
Wscript.echo "new order received from myorder3"
end sub
Windows Script Components
Windows Script Components の .wsc ファイルは、 .wsf ファイルと同じコンポーネントによって
処理されます。したがって、Events 属性を含む <object> 要素が同
じ機能を提供します。ただし、Wscript.CreateObject メソッドと Wscript.ConnectObject
メソッドは WSH 固有のものなので、WSH の外部では使用できません。
まとめ
イベントの結び付けに何が使用できるかを理解すれば、イベント ドリブンのプログラミングにより
アプリケーションのスクリプトの作成がかなり容易になります。ここまで示してきたように、イベント ハ
ンドラを記述するための最適なメカニズムを判断することはかなり複雑になる可能性があります。
各アプローチの相対的な長所を調べ、スクリプトを作成する作業が過度に複雑にならないように
必要条件を満たすアプローチを選択することに注意を払います。私たちは、スクリプトの作成を容
易にするためのフィードバックやご意見をいつもお待ちしています。いつでもご自由に(英語で) msscript@microsoft.com にメールをください。また、msnews.microsoft.com
のニュースグループもご利用ください。
|