特集 Visual Basicドキュメンテーション技術

ActiveXコントロールを使った
Webアプリケーションからの印刷処理

秋月巌 AKIZUKI, Iwao  



イントラネットの普及

 コンピュータ雑誌では、インターネット、イントラネット関連の技術紹介が花盛りだが、現場への浸透はまだまだ遅れている。これはマスコミの軽薄な論調やベンダー主導のテクノロジーの進歩に対する、ユーザーの慎重な姿勢だということができるだろう。だが、それ以上に、新しいスタイルのテクノロジーに対する消極的な姿勢も関係しているのではないだろうか。

ニューテクノロジーがもたらす不安

 イントラネットやWebベースで動作するアプリケーションは、一見、先端技術に依存しているように見えるかもしれないが、その基盤となる技術は古いテクノロジーの焼き直しである。ただ、最近はWebを含めて、なんでもかんでも複雑化する傾向があるので、テクノロジーのコアになる部分が以前よりも外からは見えにくくなっている。
 ニューテクテノロジーがもつ不安定さは、そのアイデアの革新性からよりも、複雑化した環境からくる場合が多い。つまり、新しく提供されたパラダイムが複雑に見えるとしたら、その技術には距離を置いて接するべきだということだ。

Windowsネットワークからイントラネットへ

 その点イントラネットは、基本的にはシンプルに具現化されているメカニズムである。Webサーバー側は要するにファイルサーバーに過ぎない。それをマルチメディアデータとして表示するのは、ブラウザの役割である。もっとも、最近のブラウサは複雑化し、その分、重量アプリケーションと化しているが、HTMLページを表示する機能自体は決して複雑なものではない。
 Windowsネットワーク環境なら、Microsoftが無償で提供するWebサーバーを使えば、ネットワークをイントラネット化するためのコストはかからない。特にファイル配布システムとしてのイントラネットは優れている。イントラネットというと、どうしてもHTMLページの表示を意識してしまうが、サイトにファイルを保存しておき、それらをHTMLページから簡単にダウンロード可能にできるメリットは大きい。

Webアプリケーションの必然性

 イントラネット環境の整備はデベロッパーの作業というよりは、ネットワークエンジニアの仕事である。環境が整ってから、初めてアプリケーションが要求される。もっともWebサーバーを利用して掲示板として利用したり、ファイルの配布に使うだけならば、Webサーバーを立ち上げるだけでよい。しかし、最近、いくら便利なHTMLエディタが普及したといっても、それらの管理をエンドユーザーがマニュアルで行なうのは負担が大きい。何かしら、作業を自動化するためのアプリケーションが必要になる。

Active Server Pagesプログラムで印刷?

 本誌でもActive Server Pagesを使ったアプリケーションの開発手法については何度か扱ってきた。Active Server Pagesは、従来のアウトオブプロセスで動作するCGIに変わるサーバースクリプティング環境である。MicrosoftのWebサーバーでないと動作しないのが欠点だが、Window 95でも動作するという強みもある。
 ただ、Active Server PagesでもアウトオブプロセスのCGIによるプログラミングでも、最後に残るのは印刷処理の問題である。もちろん、Webブラウザには印刷機能があり、それを利用することでページの内容を印刷することはできるのだが、印刷のスタイルや印刷時のふるまいをプログラムから制御することはできない。印刷の指示をWebサーバーに送信すればサーバーが処理をするようなケースを除いて、印刷処理はすべてクライアントでコントロールする必要があるからである(図1)。

図1:サーバーが印刷するか、クライアントが印刷するかの違い
444*231

ActiveXコントロールの利用

 このような場合に、特別な意味あいをもってくるのが、ActiveXコントロールやプラグインのような機能である。ここでは、プログラムからの印刷制御を実現するために、ActiveXコントロールを使用する方法を紹介する。当然、ここで紹介する手法はNetscape Navigatorで使うことはできない。
 ActiveXコントロールは、WebページやVisual Basicプログラムの中に埋め込まれるコンポーネントだが、デザインによっては完全に独立したアプリケーションとして動作する。つまり、ActiveXコントロールを使えば、Windowsアプリケーションからできることのほとんどは、Webアプリケーションで実現することができる。
 また、Webアプリケーションで利用する場合にはCABファイルにまとめておくことで自動的にダウンロードとインストールが可能なる(これは失敗する率が高いが、大抵は再試行することで成功する)。つまり。Webページをアクセスする要領でプログラムを設定したりオペレーションすることができる。

図2:ActiveXコントロールの動作図
354*231

JavaアプレットとActiveXコントロール

 ActiveXコントロールの話が出るとJavaの話もしなければいけないような気がするのは、単なる習性だろうか。たとえばJavaアプレットはActiveXコントロールに該当する役割を果たしている。コンポーネントとしてはJavaBeansが存在する。ではJavaアプリケーションに相当するものがActiveX.EXEか、というとそうではない。ActiveXコントロールをVisual Basicのフォームに貼り付けて標準.EXEとしてコンパイルすれば、これでアプリケーションが完成する。もちろん、ActiveX.EXEとしてコンパイルしてインターフェイスを公開してもよい。
 いずれにしても、ユーザーに公開されるスタイルが違うだけで、ActiveXコントロールがアプリケーションと同等の機能をもっていることがわかると思う。もちろん、コントロールはメソッドやプロパティによってアプリケーションプログラミングインターフェイス(API)が公開されているので、コンテナから操作することができる。
 ところで、Microsoftが発売しているJava開発ツールであるMicrosoft Visual J++ではActiveXコントロールを作成することができる。Visual J++で作ったActiveXコントロールは、あくまでもActiveXコントロールであって、Javaが提供するテクノロジーとは無縁である。つまり、言語仕様としてのJavaをActiveXコントロール開発のために利用している形になる。現在、言語としてのJavaは、特に完成度の高い言語使用を誇っているので、ActiveXコントロールの開発に、このような選択肢が加えられたことは喜んでいいだろう。もっとも、ActiveXコントロールの開発ツールとしてVisual J++はVisual Basic5.0に遠く及ばないので、Visual Basicデベロッパーが選択する対象にはならない。

ブラウザ内で動作するコントロールの制御

 ActiveXコントロールをWebブラウザ内で利用する場合、コントロールを制御するにはVBScriptかJScript(Microsoftが提供するJavaScript互換言語)のようなクライアントスクリプトを使うことになる。これらの言語エンジンは、Internet Explorerのモジュールに同梱されている。
 ただ、これらの言語エンジンモジュールの完成度は低い。また、実行コードはHTMLファイルの中にテキストとしてダウンロードされてくる。すなわち、中間コードとしてすらコンパイルされていない。当然、実行速度も遅いので、クライアントスクリプトの使用は最小限に抑えた方がいいだろう。
 だからというわけではないが、本来、クライアントスクリプトはActiveXテクノロジーの中で重要な位置づけをもち、実際に有用なのだが、どうも今ひとつ注目されていないようである。一般の認識として、HTML内に記述して、簡単な操作を行なうというイメージがあるからだろう。しかし、クライアトンスクリプトの真の目的は、ActiveXコントロールを操作することにある(図3)。
 つまり、Visual BasicアプリケーションにおけるVisual Basicと同じ役割を担うことになる。クライアントスクリプトを利用することで、サードパーティが提供するコントロールの機能をブラウザ内で使用したり、あるいはActive Server PagesとActiveXコントロールの連携が可能になる。
 もっとも、最近のMicrosoftは、WebブラウザにおけるActiveXコントロールの有用性よりも、Dynamic HTMLのサポートを強調している。Dyanmic HTMLとActiveXコントロールは、まったく異なるパラダイムによりクラアントでのプログラム実行を実現しているため、それぞれの長所と短所がある。

図3:Webブラウザ内で動作するActiveXコントロールをクライアントスクリプトで制御
444*158

Active Server PagesとActiveXコントロールの連携

 では、何故、Active Server PagesのようなサーバーサイドスクリプトでActiveXコントロールを制御するときにクライアントスクリプトによる仲介が必要になるのだろうか。それはサーバーのスクリプトではクライアントのコントロールを制御できないからである(図4)。例外としては分散処理を用いた場合とクライアントとサーバーが同一マシンにある場合があるのだが、どちらも例外的な環境ということができるだろう。
 そのため、サーバースクリプト取得した結果を、クライアントのActiveXコントロール(たとえばラベルコントロール)に反映させるためには、コントロールに値を導入するためのスクリプトをサーバーで動的に作成する必要がある。

図4:それぞれのスクリプティング環境は、それぞれのオブジェクトしか扱えない
444*225

ActiveX Documentsとの違い

 サーバーでスクリプトを動作させるというこの方法は、十分に実用的でパワフルなのだが、サーバーサイドスクリプト、クライアントスクリプト、ActiveXコントロールの作成という3つの方法を理解しなければならないという煩雑さも持ち合わせている。ところで、本誌を通読している読者ならば、Visual BasicならActiveX Documentsが作成できることはご存知だろう。
 ActiveX Documentsならば、こんな面倒なことをしなくてもVisual Basicによるプログラミングを学習するだけでWebアプリケーションを作成できる。しかも、プログラムの動作にHTTPを使用しないので、より高い堅牢性を確保できる。ActiveX Documentsは、いわばフルスペックのVisual Basicアプリケーションをイントラネットベースで配布し、Webブラウザ内で動作させる仕組みのことである。この方法はあまりにもイントラネット的でないが、イントラネットのメリットを、既存の方法のメリットを失うことなく享受するすばらしいアイデアだ。
 それならば、ActiveXコントロールとActive Server Pagesを連携させなければならない理由とは何なのだろうか。これはどちらかというと結果の問題というよりは、方法論の問題だということができる。ActiveX DocumentsがVisual Basicの拡張としてイントラネットシステムを実現しているのに対して、ASP + ActiveXコントロールはMicrosoftのインターネットテクノロジーのサイドからVisual Basicを利用している形になる。
 Active Server Pagesはリスト表示の際に、コントロール可能なサーバーサイドカーソルが簡単に利用できたり、他のWebページとの統合性が高いなどの特徴がある。最終的には、より目的に適した方法か、開発に慣れた方法を使うことになる。

コントロールを利用して印刷するサンプルアプリケーション

 実例をご覧いただこう。図5はコントロールを利用して印刷機能を提供するWebアプリケーションページである。データベースのテーブルの内容をWebページに表示し、ボタンをクリックすることでテーブルの内容を印刷する。
「印刷コントロールです」と表示されている部分がActiveXコントロールとしてWebページに埋め込まれている。コントロールは印刷機能を提供するだけでユーザーが操作することはないので、本来なら非表示にすべきである。
 このActive Server Pagesファイルのソースコードがリスト1である。Active Server PagesのVBSコードを網掛け、クライアントスクリプトを太字で表記しているので、プログラムの構造を理解してほしい。ソース中でクライアントスクリプト部分にActive Server Pagesのコードが混ざっていることがわかると思う。この部分でクライアントスクリプトを生成して、ActiveXコントロールを制御している。
 リスト2はテーブルの内容を取得し、生成されたクライアントスクリプトである。リスト1ではループになっている部分が展開され、値をコントロールに渡すために商品名と商品コードが列挙されている。クライアントからはテーブルはデータベースにアクセスすることができないので、データをすべてクライアントスクリプトの代入コードの右辺として列挙する必要がある。

図5:Internet Explorerから印刷をするページ
464*589

リスト1:サンプルプログラムのASPコード(print_sample.asp)
<HTML><HEAD><TITLE>印刷サンプル</TITLE></HEAD>
<BODY BGCOLOR="ffffff">
<%
    Set dbConnection = Server.CreateObject("ADODB.Connection")
    dbConnection.Open "order"
    Set rsSyohin = Server.CreateObject("ADODB.Recordset")
    SQLcmd = "SELECT *  FROM Syohin"
    rsSyohin.Open SQLcmd,dbConnection, 3, 1 '静的スクロール、読取り専用
    %>
<SCRIPT LANGUAGE="VBSCRIPT" > Sub cmdPrint_onClick() ret = MsgBox ("印刷してもよろしいですか?",4) If ret = 6 Then
<%  i = 1
    Do While Not rsSyohin.EOF %>
DOCUMENT.FRM1.ucInsatu1.SetCode(<%=i%>) = "<%=rsSyohin("syohin_code")%>" DOCUMENT.FRM1.ucInsatu1.SetName(<%=i%>) = "<%=rsSyohin("syohin_mei")%>"
<%      rsSyohin.MoveNext
        i = i + 1
    Loop %>
DOCUMENT.FRM1.ucInsatu1.ListPrint End If End Sub </SCRIPT> <FORM NAME="FRM1"> <OBJECT ID="ucInsatu1" WIDTH=119 HEIGHT=23 CLASSID="CLSID:2E90C18E-54D0-11D1-81D9-008098E04899" CODEBASE="cab/insatu.cab#version=1,0,0,0"> <PARAM NAME="_ExtentX" VALUE="3149"> <PARAM NAME="_ExtentY" VALUE="609"> </OBJECT> </FORM> <INPUT TYPE="BUTTON" NAME="cmdPrint" VALUE=" 印刷 "> <TABLE BORDER=1> <TR> <TH ALIGN="LEFT"><H5>商品コード</H5></TH><TH><H5>商品名</H5></TH> </TR>
<% rsSyohin.MoveFirst
   Do While Not rsSyohin.EOF
 %>
<TR>
<TD><FONT SIZE=2>
<TD><FONT SIZE=2>
<%=rsSyohin("syohin_code")%>
<%=rsSyohin("syohin_mei") %>
</FONT></TD>
</FONT></TD>
</TR>
  <%
     rsSyohin.MoveNext
  Loop %>
</TABLE> </BODY> </HTML>

リスト2:Active Server Pagesによって生成されたクライアントスクリプト(print_sample.aspが生成)

<SCRIPT LANGUAGE="VBSCRIPT" >
Sub cmdPrint_onClick()
    ret = MsgBox ("印刷してもよろしいですか?",4)
    If ret = 6 Then

        DOCUMENT.FRM1.ucInsatu1.SetCode(1) = "12"
        DOCUMENT.FRM1.ucInsatu1.SetName(1) = "さらさら飴"
                     |
          中略
                     |
        DOCUMENT.FRM1.ucInsatu1.SetCode(32) = "423"
        DOCUMENT.FRM1.ucInsatu1.SetName(32) = "まるぼーろ"

        DOCUMENT.FRM1.ucInsatu1.ListPrint
	End If
End Sub
</SCRIPT>

サンプルのクライアントスクリプト

 イベントプロシージャの開始を指定する次のコードは、Visual Basicと共通の書式によって記述されている。アンダースコアの前の部分(cmdPrint)が対応するオブジェクト名で、後半が(onClick)がイベント名である。

Sub cmdPrint_onClick()

つまり、このイベントプロシージャはcmdPrint(印刷ボタン)がクリックされたときに実行される。
 次の2行ではメッセージボックスの表示と、ユーザーの反応によって処理を分岐している。

ret = MsgBox ("印刷してもよろしいですか?",4)
If ret = 6 Then

このコードで定数を用いずに、数字を指定しているのはVBS1.0のモジュールが定数に対応していないからである。Internet Explorer3.0xをインストールした状態では、VBSのモジュールは1.0だが、最新のDeveloper StudioやActive Server Pagesをインストールすると自動的(無警告)にVBS2.0に上書きされる。そのため、開発者の環境では動作するが、ユーザーの環境では動作しないというトラブルが発生する。
 次の2行では印刷するためのデータとして、コントロールのプロパティに値を設定している。SetCodeプロパティやSetNameプロパティは、Visual Basicによって作成したプロパティである。

DOCUMENT.FRM1.ucInsatu1.SetCode(1) = "12"
DOCUMENT.FRM1.ucInsatu1.SetName(1) = "さらさら飴"

 最後に実行しているListPrintメソッドでは、配列に格納されている値をプリントキューに送信している。

DOCUMENT.FRM1.ucInsatu1.ListPrint

この処理によって実際のブリント処理が実行される。

ActiveXコントロール

 印刷機能を提供するActiveXコントロール(図6)は、前出のクライアントスクリプトでも紹介したように、SetCodeプロパティ、SetNameプロパティ、ListPrintメソッドという3つのプログラミングインターフェイスを公開している。
 リスト3ではプロパティに設定されたデータを配列に格納している。リスト4は配列の内容を印刷するための処理が記述されている。このプロシージャはクライアントスクリプトでListPrintが呼び出されたときに、その時点で配列に格納されているデータを印刷する。
 印刷の処理にはPrinterオブジェクトを使用している。PrinterオブジェクトのCurrentY、CurrentXプロパティに座標を指定してから、出力する内容をPrintメソッドの引数として渡しプリントキューに送信する。印刷内容をすべて出力したら、 EndDocメソッドを使って実際のプリント処理を開始する。

図6:作成中のコントロール
151*76

リスト3:プロパティに設定された値を配列に格納する(SetCodeプロパティ、SetNameプロパティ)
Public Property Let SetName _
 (ByVal Index As Integer, ByVal New_Data As String)
    ReDim Preserve syohin_mei(Index)
    syohin_mei(Index) = New_Data
End Property
Public Property Let SetCode _
(ByVal Index As Integer, ByVal New_Data As String)
    ReDim Preserve syohin_code(Index)
    syohin_code(Index) = New_Data
    syohin_count = Index
End Property

リスト4:印刷を実行するListPrintメソッド
Public Sub ListPrint()
    Dim i As Integer
    'スケールモードをキャラクタに設定
    Printer.ScaleMode = 4
    Printer.FontName = "MS Pゴシック"
    Printer.FontSize = 16
    Printer.CurrentY = 8
    Printer.CurrentX = 31
    '見出しを印刷
    Printer.Print "商品一覧リスト"
    '日付を印刷
    Printer.FontSize = 10
    Printer.CurrentY = 8
    Printer.CurrentX = 60
    Printer.Print Date
    '商品コードを印刷
    Printer.CurrentY = 15
    Printer.CurrentX = 20
    Printer.Print "商品コード"
    '商品名を印刷
    Printer.CurrentY = 15
    Printer.CurrentX = 50
    Printer.Print "商品名"

    For i = 1 To syohin_count
      '商品コードを印字する行を設定
      Printer.CurrentY = 15 + i
      '商品コードを印字する桁位置を設定
      Printer.CurrentX = 20
      '商品コードを印字
      Printer.Print syohin_code(i)
      '商品名を印字する行を設定
      Printer.CurrentY = 15 + i
      '商品名を印字する桁位置を設定
      Printer.CurrentX = 50
      '商品名を印字
      Printer.Print syohin_mei(i)
    Next
    '印刷を終了
    Printer.EndDoc

End Sub

Printerオブジェクトの限界

 実際にはPrinterオブジェクトを使って実用的なプログラムを作成するのは、かなりの労力が要求される。Visual Basicに付属しているCrystal Reporは、Webアプリケーションではまったくの無力である。結局、サードパーティの製品の力を借りることになる。
 現在ではいくつかの印刷用のActiveXコントロールが発売されているが、Crystal repotのように、帳票印刷機能として独自のデータベースアクセス機能を備えているものは使用しにくい。純粋に印刷機能を強化するための機能が提供されているものがよい。図7は文化オリエント社のVS-Viewを使ってWebアプリケーションにプレビュー機能を追加した例である。印刷機能自体も強化されているので購入する選択肢のひとつになるだろう。
(本稿で解説したサンプルプログラムは付録CD-ROMの\VBMAG\AXPRINTディレクトリに収録しています:編集部)

図7:サードパーティ製のActiveXコントロールを使ってプレビューを実現
570*428


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


PCDN LOGO