ISAPI 200%活用技法

CGIとASPの利点をもったISAPIアプリ作成法

初音 玲 HATSUNE, Akira



 IISにおける

 Webアプリケーションの基本

 IISでWebアプリケーションを作るとき、どんな技術を用いたらよいのだろうか。過去の技術となったIDC/IDXをいまさら選択する人はいないだろう。Webサーバーに依存しないようにするためにCGI(Common Gateway Interface)を選択したり、Microsoft Script Debuggerなど、デバッグ環境が整備されたことに伴なってActive Server Pages(ASP)を採用する場合もあるだろう。また、Visual Basic 6.0から追加されたWebClassを使って、使い慣れたVisual Basic(以下VB)の開発環境で、WebアプリケーションをIISアプリケーションとして作成することを選ぶかもしれない。これらの方法とISAPIではどのような点が異なるのだろうか。

 CGIの概要


 CGIは、外部プログラムを呼び出す技術のひとつで、ほとんどのWebサーバーでサポートされている。また、Perlなどのスクリプト言語で記述することが多いので、CGIスクリプトなどと呼ばれるときもある。もちろん、C言語などで記述することも可能で、要は、標準入出力をサポートしているのであれば、どんな言語でもCGIを作成することができる(図1)。


 このCGIをVBで作成しようと考えると、なかなかやっかいな問題が発生する。それは、Visual Basicには標準入出力先とのI/Oを行なう機能が備わっていないのだ。そこで、Win32 APIが活躍する。使うAPIは、


の3つだ。Webクライアントからの入力がないのであれば、GetStdHandle APIとWriteFile APIだけでも作成できる(サンプルCGI、リスト1)。


 WriteFile APIを使うときには、UnicodeとシフトJISの関係に注意を払う必要がある。それは、VBの32bit版では、Windowsと同様に文字の内部コードとしてUnicodeが使われているためだ。要は、実際にVBが意識しているのは、シフトJISではなくUnicodeだということだ。もちろん、ファイル入出力などでは、VB自体が外部コードであるシフトJISに変換しているので、意識する必要がない。しかし、APIを使うときには、文字列をUnicodeとして渡すのか、それともシフトJISに変換して渡すのか、きちんと意識しなければならない。今回のサンプルでも、WriteFile APIに文字列を渡す前に、シフトJISにコード変換している。コード変換したものを文字列に入れようとすると、そこでシフトJIS→Unicode変換が自動的に起こってしまうので、バイト型配列に代入して、自動コード変換が発生しないようにしている。
 このようにして作成した標準EXEをIISの仮想ディレクトリのどこか(たとえばSCRIPTSディレクトリ)にコピーして、その仮想ディレクトリのプロパティの設定で、アクセス権として「実行」を許可すればよい。そして、Webブラウザより、


のようなURLでサンプルプログラムを指定すれば、ブラウザには


と表示される(リスト2)。


 CGIの問題点

 CGIの問題点としては、ブラウザから依頼された単位でCGIの起動と終了が起こることだ。そのため、アクセスが集中したときにレスポンスが低下しやすい。
 また、VBでCGIを作ったときもそうだが、Windows環境では、デバッグするのが面倒な点も問題になってくる。これは、UNIXなどと異なり、WindowsではDOS窓などで標準入出力をサポートしていないことが原因だ。

 VBでCGI


 VBでCGIを作る利点は、余りないように感じる人も多いだろう。確かに、CGIの移植性を損なってまでVBに固執する必要はないかもしれない。しかし、Visual Basicのノウハウやコードなどが蓄積されているのならば、VBによるCGIを検討してみる価値はあるだろう。しかも、Web ClassなどのようにVB6.0以降でのみ使える新技術ではないので、VB4.0(32bit)以降ならば、どのバージョンでも作成することができる。また、変数がすべてバリアント型であるASPのように、処理速度が低下したり、型合わせのためにプログラムの手間がかかったりすることもない。
 試しに、Oracle Objects for OLE(以下oo4o)を使って、Oracleデータベースからデータを取得して表示するサンプルを作成したみた(リスト3、4)。見なれたコードのままで、Webアプリケーションを作成できるということが一目瞭然だ。oo4oからのエラーについても、HTMLのBODY部に文字列として埋め込んでしまえばよいだろう。もちろん、RDO用に書き換えてSQL ServerをRDBMSとすることも可能だ。このときは、SQL ServerやODBCドライバからのエラーに半角カナ文字が含まれているので、StrConv関数を使って、全角文字に置き換える必要がある。もっとも、そうすると英字も全角になって、カッコ悪いエラー表示画面になってしまうが、それは仕方がないことだろう。
 なお、デバッグについても、標準出力に送る文字列を「Debug.Print」を使って表示することで比較的簡単に行なうことができる(リスト5)。極めて単純な方法だが、VBのIDEを使ってのデバッグもスムーズに実施できるはずだ。


 VBでCGI

 標準入力を活用する

 さて、VBによるCGIのサンプルをもう1点紹介する。ブラウザからの入力をサポートした例だ(サンプルCGIStdIn)。ブラウザからの入力を判定には、大きく分けて2通りの方法がある。環境変数を参照する方法と標準入力からデータを受け取る方法だ。

 環境変数を参照する

 CGIがサポートされていれば、ある程度標準的な環境変数にブラウザからの情報が格納される。一般的な環境変数を表1にまとめてみた。この環境変数をVBで参照するには、Environ関数を使う(リスト6)。
 もしCGIアプリケーションが、HTMLフォームの情報をGETメソッドで受け取るならば、フォームに設定した情報は、環境変数[QUERY_STRING]に設定される。しかし、GETメソッドを使う形式では、URLにその情報が表示されてしまう。これは、格好が悪いだけではなく、ダイレクトにパラメタ付きでCGIを起動することができるということになる。これでは、具合の悪いこともある。このようなことを回避するためには、HTMLフォームからCGIを起動するもうひとつの方法、POSTメソッドを使う。そして、そのときに情報を受け取る方法が、標準入力なのだ。


 標準入力からデータを受け取る

 表1にあるように、標準入力で受け取れるデータが存在するかは、[CONTENT_LENGTH]環境変数の値を参照すればよい。そして、実際に標準入力からデータを受け取るには、GetStdHandle APIとReadFile APIを使う(リスト7)。


 さて、問題なのは、標準入力から受け取った情報が、シフトJISコード系にはなっていないという点だ。そこで、Visual Basicが理解できるコード系に変換する必要がある(図2)。それが、URLDecode関数だ(リスト8)。VB6.0からはこのような処理を行なうのに便利な機能が追加されている。これら新機能を使わない手はないのだが、今回はVB4.0/5.0でのプログラムの作成も考えて、条件コンパイル定数により、複数バージョンに対応したソースコードにしている。VB6.0以外の方は、CGIStdIn.basファイルの先頭にある


を削除して欲しい。
 このようにして作成したCGIアプリケーションを呼び出すためには、リスト8のようにHTMLフォームを使って、POSTすればよい。



確かにサンプル3は、VBのバージョンに依存しないつくりにはなっている。しかし、お使いのIISやPWS(Personal Web Server)のバージョン、OSのバージョンやサービスパックが、VBのバージョンと整合性があるかをきちんと判断した方がよいだろう

 さらにもう一工夫

 サンプル3では、CGIアプリケーションが呼び出されるたびに、Oracleへの接続と切断が行なわれる。これはとても非効率的だ。そこで、前号の特集で取り上げたMTS(Microsoft Transaction Server)を活用するとよいだろう。MTSのコネクションプーリング機能を使って、CGIアプリケーションの起動や終了とは無関係に、DCOMで通信する先のMTSオブジェクトは、Oracleとの接続を確保しつづけてくれる(図3)。


 IISでCGI利用の注意点


 認証を行なわないでアクセスしている(匿名アクセス)と、IISが稼動しているOSは「IUSR_サーバー名」アカウントのユーザーとして、アクセスしている人を認識している。この「IUSR_サーバー名」アカウントには、IISインストール直後は、ローカルログオン権限とゲスト権限しか割り当てられていない。一見、ある程度のセキュリティを確保できているように見えるが、フォルダやファイルに対して、「Everyone」の権限が設定されていると、匿名アクセスのユーザーからも操作が可能になってしまう。


などの配慮が必要になってくる。最悪の場合、IIS実行権があるフォルダに対して、[他のファイルを変更する]CGIをアップロードして、システムを破壊することだって可能なのだ。
 これは、CGIを使ったときだけではなく、NTFSのデフォルト値なども絡んだWindows NTセキュリティモデル全体の問題だ。Windows NTをインターネットに晒すべきではないという意見は、セキュリティホールがあるという以前に、システムのデフォルト値の甘さに端を発している。

 ISAPIアプリケーション概要


 ISAPIアプリケーションには、ISAPIサーバー拡張とISAPIフィルタの2種類の形態がある。その両者に共通しているのは、DLL形式のプログラム(ISAIアプリケーション)とIISを繋ぐ技術だと言うことだ。よって、ISAPIアプリケーションを使ったときの利点として、CGIで問題になってくるプロセス生成のためのオーバーヘッドが軽減されることがある。このプロセス生成のオーバーヘッドは、ActiveX DLLとして動作するASPでも同様に軽減できるので、ISAPのみの利点ではない。しかし、そのつどスクリプトを解釈しながら動作するASPに比べ、ネイティブコンパイル後のDLLであるISAPIアプリケーションでは、ロジック実行のオーバーヘッドが軽減される。
 つまりISAPIアプリケーションは、ASPの利点(少ないオーバーヘッドでプロセスを起動可能)とCGIの利点(少ないオーバヘッドでロジックを実行可能)の両方を同時に実現できるのだ。

 ISAPIアプリケーション

 〜ISAPIサーバー拡張〜

 ISAPIサーバー拡張は、先ほどのCGIアプリケーションのように、フォームに値を記入(もちろん、URLに直接指定することもできる)して、[Submit]ボタンをクリックすることで起動する(図4)。


 このISAPIサーバー拡張をVisual Basicで作成するときは、越えなくてはならない大きな山がある。それは、"ISAPIサーバー拡張は、DLL形式の実行ファイルとしてコンパイルしなければならない"点だ。もちろん、ここで言うDLL形式とは、COMインターフェイスを使ったActiveX DLLではなく、純粋なDLLだ。この形式の実行ファイルをVBで作ることはできない。そこで考えられるのが、DLL形式の実行ファイルをVisual C++で作成して、その中からCOMを使ってVBで作成したActiveX DLLなりActiveX EXEを呼び出すという方法だろう(図5)。


 そこまでして、VBで作る必要があるかというもっともな疑問も生じる。確かに何もない状態から、図5の「橋渡しDLL」を自作するのならば、そのままVisual C++を使ってISAPIサーバー拡張の作成に邁進した方が幸せになれる。
 しかし、「橋渡しDLL」が市販されていたらどうだろうか。これならば、VBでISAPIサーバー拡張を作成する価値が俄然出てくるであろう。
 勘のよい方は気づかれたかもしれないが、「橋渡しDLL」は市販されている。そして、市販されているからこそ、今回の特集でISAPIを取り上げようと思ったのだ。
 特に今回取り上げる2つの製品は、テスト方法にまで気を使った製品で、テスト効率の面からも、標準入力を使ったCGIアプリケーションよりも性能が高い。

 ISAPIアプリケーション

 〜Web Extender〜

 まずは、まさに「橋渡しDLL」のアイデアそのものを製品化したようなアグレッシブ株式会社の「Web Extender」を紹介する(http://www.aie.ne.jp/extender/)
 Web Extenderの本体は、ISAPIサーバー拡張であるGWIISOLE.DLLだ。URLで、GWIISOLE.DLLに引き続いて、


と記述すれば、GWIIDOLE.DLLは、指定されたActiveX DLLのクラスのメソッドをCOMを経由して呼び出す(図6)。このメソッドは、名前こそ自由に付けることができるが、パラメータの個数や型は決まっている。メソッド名としてActionを指定したときは、該当クラスの中に、


と記述して、Web Extenderからの出入り口を定義する。とくに第二パラメータは重要で、メソッドの戻り値として使用される。この戻り値は、Web Extender上でHTMLとみなされ、それをブラウザに送り返すことになる。要は、HTMLを標準出力に渡す変わりに、変数に設定してGWIISOLE.DLLに返却すれば良いということだ。
 また、Web Extenderの面白いところは、クラスが呼び出されるときに、CGI環境変数の値を同名のPublic変数に設定する点だ。たとえば[QUERY_STRING]環境変数の値が欲しいときは、クラスの変数宣言部に、


と変数宣言をしておけばよいのだ。これは便利な機能だ。
 なお、テスト方法としては、GWIISOLE.DLLの代わりに製品に付属しているテストクライアントを使って、ActiveX DLLを呼び出してテストをする。もちろん、事前にバイナリ互換をもったVBのIDEでソースプログラムを実行しておいて、テストクライアントとIDEを連携してステップ実行などを行ないながらテストすることもできる。*1


 ISAPIアプリケーション

 〜VB-WEB〜

 もう一本の製品は、アドバンス技研株式会社の「VB-WEB」だ(http://www.adv.co.jp/)。この製品のアプローチは、「橋渡しDLL」+αという感じだ(図7)。Visual Basicでは、ActiveX DLLやActiveX EXEではなく、標準EXEとして実行ファイルを作成する。そして、その標準EXEをISAPIサーバー拡張であるVB_Bridge.DLLから起動する。このとき、インターフェイスにはすべてファイルを使っている。雰囲気としては、よりCGIに近い形式だろう。VB-Webの利点は、V Bで作ったロジックに障害があっても、IISが巻き添えを食う確率がCGI並みに低いということだ。もちろんそのために純粋な「橋渡しDLL」の方式よりもプロセス生成のオーバヘッドが存在する。しかし、安全性を確保したいという向きにはお勧めの方式だろう。そして、Win32APIを使ってCGIアプリケーションを作成するよりも、デバッグ環境が整備されているという点も見逃せない。
 VB-WEBを使うときには、URLで指定するのではなく、必ずHTMLフォームを使う。<FORM>タグのACTIONにVB_Bridge.DLLを指定して、INPUTタグのNAMEに"VBEXE"、VALUEに標準EXEの実ディレクトリにおける位置をフルパスで指定する。このVALUEへの指定方法だけはいただけない。なんとかIISの仮想ディレクトリに対応して欲しいものだ。
 さて、VB-WEBのテスト方法もユニークだ。VB_Bridge.DLLではなくVB_Bridge2.DLLを指定することで、捜査結果をファイルに出力する。そのファイルを基にIIS環境がないところでもVBのIDEのみでテストおよびデバッグが可能になる。一見非効率に見えるが、実際に運用を行なっているようなときには、効率的な方法だ。


 ISAPIアプリケーション

 まとめ

 今回2つの製品を紹介したが、同じような技術を使いつつ、VBで作成したロジックのプロセスをどのように扱うかに関しては、別々の回答を導き出している。それぞれの回答のどちらがよいかは、作成する業務により異なってくるだろう。安全性とパフォーマンスのバランスを考慮しながら判断して欲しい。なお、どちらの製品を用いても、ASPよりもパフォーマンスが高いことをお伝えしておく。

 ISAPIアプリケーション

 〜ISAPIフィルタ〜

 ISAPIフィルタは、プログラムをサブクラス化してWindowsメッセージをフックするように、IISとクライアントの間のHTTPプロトコルをフックする。このISAPIフィルタこそ、CGIやASPでは実現できないISAPIの独自性だ。
 そして、ISAPIフィルタを使うことで、ユーザーごとのホームページを


という「~(チルダ)」付きのURLで管理することができる。つまり、「~」があればuseridに対応したホームディレクトリのpublic_htmlに位置付けすればよい。
 ただし、残念なことに、前記2製品をもってしても、ISAPIフィルタをVBで作成することはできない。そもそも、無理やりVBでプログラムしなくても、Visual C++のISAPI Extension Wizardを使って、自動的にISAPIフィルタのイベントごとの関数定義を生成することができる。そしてあとは、イベントに対応した関数定義の中にロジックを記述すればよい。ISAPIフィルタのようにAPI中心のプログラムならば、Visual C++の方が適しているし、MFCなどのライブラリをスタティックリンクして、ひとつの実行ファイルとしてコンパイルすることもできる。
 このスタティックリンクは、実行ファイルのサイズが大きくなるという不利な点もあるが、その他のDLLなどが不要になるため、DLLの不整合により動作不良になったり、または、自身をインストールする際に、互換性のない同名DLLをインストールしてしまい環境を壊すといったこともない。年々、パソコンのメモリやHDDが安価で高性能になってきているので、スタティックリンクの弊害は、ほとんど影響を及ぼさなくなっているのも朗報だ。きちんとした市販アプリケーションを販売しているところでは、このスタティックリンクを行なっていることが多いようである。VBの次版では、ぜひスタティックリンクを実装して欲しいと思う。そのためには、肥大化したVBのランタイムDLLを、どう分割するかが問題になってくるだろう。

 最後に


 冒頭で列挙したWebアプリケーションの作り方にはひとつの法則がある。それは、IDC/IDX、CGI、ASPおよびISAPIは、すべてサーバーサイドで動作する仕組みだということだ。つまり、Webサーバー内部でブラウザからの要求に基づいてHTMLを組み立ててそれを返却するということだ。これがWebアプリケーション開発の成功のカギだ。
 サーバーサイドで標準的なHTMLを出力することにより、ブラウザが解釈する部分を極力抑えることで、ブラウザ間の互換性のなさを吸収して、ある程度ブラウザに依存しないアプリケーションが作れる。さらにどうしてもブラウザに依存した処理を記述しなければいけないときは、クライアントサイドスクリプト(VBSctiptやJScript、Java Script、DHTML、スタイルシートなど)でブラウザを判断するのではなく、サーバーで判断してブラウザにあったHTMLを出力することも可能だ。こうすることで、"自分のブラウザでは必要ないコードが送られてくるために、ネットワークトラフィックが増大したり、Webページが開くまでに時間が余計にかかったり"といったことがなくなるのだ。
 よって、ホームページを作っている自社社員に片手間で任せられる安易で安価な構築法として、Webアプリケーション構築を捉えるべきではないだろう。プロバイダに個人でホームページを作るときには、プロバイダのセキュリティ方針などで、サーバーサイドでの実行が著しく制限されていることが多い。そのため、勢いクライアントサイドスクリプトに頼るしかない。同じような技術ではあるが、そこで使われている手法は全然異なるのだ。きっちりした設計と作成技術をもった個人なり会社に協力を仰ぐべきだ。そして、他の言語に比べて、HTMLは可読性と覚えやすさが突出している言語なのだから、その後のメインテナンスなどは、自社で行なっていけばよい。それが、Webアプリケーションの利点だ。


サンプルプログラムのダウンロード  --- isapi.lzh(27KB)



VB Magazine ライブラリ | Visual Basic WorkGroup
int21 ホームページ | PCDN ホームページ


Copyright (c) 1998 int21 Corporation All Rights Reserved.
For questions or comments, please send mail to: pcdn@int21.co.jp