WindowsというOSの特徴

 読者の皆さんの中には,OSとしてWindowsを使っている人が多いことと思う。そこで,Windowsを題材として,OSが備える機能をもうちょっと詳しく説明することにしよう。現在主流となっているWindows 95/98/NT4.0のOSとしての特徴を挙げると,以下のようになるだろう。

 (1)32ビットOSである,(2)APICOMによってシステム・コールが公開されている,(3)GUIを採用したユーザー・インタフェースを利用する,(4)WYSIWYGによるプリンタ出力ができる,(5)マルチタスク機能を備える,(6)ネットワーク機能を備える,(7)データベース機能を備える,(8)プラグ&プレイによるデバイス・ドライバの自動設定ができる──。これらは,プログラマにとって意味のあることだけを示したものである。以下では,WindowsというOSの特徴と,それがプログラミングにどう影響するのかを説明する。OSの種類が異なっていても,OSが提供する機能にはそれほど大きな差はない。他のOSを使っているプログラマにも十分有益な知識となるはずだ。

32ビットOSは何が32ビットなのか

 Windowsは,32ビットOSとよく呼ばれる。この32ビットの意味は,最も効率的に処理できるデータの長さを意味している。Windowsがデータを処理する単位が,32ビットなのである。

 MS-DOSなどの16ビットOSでプログラミング経験の長いプログラマは,32ビットのデータ型を使いたがらない癖がついているものだ。32ビット・データを処理することは,16ビット・データを処理することより時間がかかると思い込んでいるためである。確かに,16ビットOSで32ビット・データを処理すると,16ビット・データを2回処理することになるので時間がかかる。メモリーやディスク容量を節約するという目的があるなら話は別だが,そうでないなら遠慮せずに32ビット・データをバンバン使ってかまわない。

 C言語には,int型というデータ型がある。int型は16ビットOSなら16ビットの整数型として解釈され,32ビットOSなら32ビットのデータ型として処理される。これは,C言語に「OSで最も効率的に処理できるデータ型をint型とする」という決まりがあるからだ。32ビットCPUを搭載したコンピュータであっても,16ビットOSを使っているなら,int型は16ビットである。データのサイズは,CPUではなくOSが決めるのだ。

システム・コールが公開されている

 Windowsは,前述のようにAPIやCOMという形でシステム・コールを公開している。

 APIは,DLLファイルの中に収録された関数セットのことである。APIの種類には,16ビットのWin16 APIと,32ビットのWin32 APIとがあり,それらの間に互換性はない。

 COMはDLLファイル,EXEファイル,およびOCXファイルの中に収録されたオブジェクトのセットのことである。COMは,オブジェクトを利用する手順を定めた仕様であり,異なるOSや開発ツールであってもCOMの仕様に準拠したオブジェクトを相互に利用することができることが特徴となっている。現状ではCOMが動作する環境はWindowsだけである。

 Windowsのシステム・コールは,現状ではAPIが中心となっているが,今後はAPIからCOMに移行していくものと思われる。これは,APIでは問題になる移植性や拡張性がCOMで解消できることと,関数であるAPIよりも,オブジェクトであるCOMの方がプログラミングが楽になるからである。

 オブジェクトは,様々な用途のプログラムで再利用可能なソフトウエア・コンポーネントとなる。細かなAPIを複雑に組み合わせるより,目的の機能を実現するソフトウエア・コンポーネントを丸ごと利用した方が,プログラミングは効率的である。

GUIを採用したユーザー・インタフェース

写真2●ユーザーは,どのような操作をしてもかまわない
逆に言えば,プログラマはどのような操作をされてもうまく動くプログラムを記述する必要がある
 GUI(Graphical User Interface)とは,ディスプレイに表示された要素をマウスでクリックすることでプログラムを操作できるユーザー・インタフェースのことだ。ユーザーにとってはありがたいものだが,プログラマにとっては,面倒のもとである。「GUIは,使って極楽,作って地獄」という川柳があるくらい難しいものなのだ。

 この難しさは,GUIではユーザーがどのような順番でプログラムを操作するかが特定できないことに起因している。写真2[拡大表示]は,筆者が原稿を書くのに利用するワープロ・ソフト,Microsoft Word 2000の「ユーザー設定」ウインドウである。3つのタブ・ページを切り換えて,必要な項目を設定するという構成である。ワープロのユーザーから見た使い勝手はよく,操作も簡単だが,これを作るプログラマの身になって考えてみると,決して簡単ではない。

 GUIを採用していないプログラムでは,プログラムの流れはプログラマが決めるものだった。ユーザーは,プログラムの流れにしたがって操作を行う。それに対して,GUIではユーザーがプログラムの流れを決める。プログラマは,どのような順序でプログラムが操作されても問題ないようにプログラムを作成しなければならない。プログラマには,大きな意識改革が必要となる。

WYSIWYGによるプリンタ出力ができる

 WYSIWYGとは,ディスプレイに表示されたものを,そのままプリンタで印刷できるということである。Windowsには,ディスプレイとプリンタを,グラフィックスを出力する同じ装置として取り扱う機能があり,それによってWYSIWYGが実現されている。

 WYSIWYGのおかげで,プログラマは楽ができる。かつては,ディスプレイの表示とプリンタの印刷のために,それぞれ別々のプログラム・コードを記述する必要があったのだ。WindowsではWYSISYGにより,一つのプログラム・コードで表示と印刷の両方が実現できる*3

図10●表示と印刷の両方を行うプログラム
 図10[拡大表示]は,直線と文字列を描画するVisual C++のプログラム・コードである。OnDrawという関数は,ディスプレイへの表示またはプリンタへの印刷が必要となったときに呼び出されるものだ。

 図10のプログラムの内容には詳しく触れないが,1つだけ,OnDrawのパラメータ「pDC」に注目してほしい。このパラメータが,グラフィックスや文字列の描画対象を示す。ディスプレイに表示を行う場合にはpDCがディスプレイを示し,プリンタに印刷を行う場合には,pDCがプリンタを示す。この切り替えは,必要に応じてWindowsが行ってくれる。

 Windowsでは,文字列もグラフィックスの一種として取り扱われている。これによって,様々なサイズやデザインの文字列を描画することが可能となっているが,逆に注意も必要だ。それは,ディスプレイに表示されている文字列を,ディスプレイのハードウエアから取得することができないということである。文字列とグラフィックスを明確に分けているOSでは,画面に表示されている文字列の位置を指定して文字コードを取得するような裏技も可能だったが,Windowsでは不可能である。その文字列を画面に描画する元となった変数から,値を取得しなければならない。

マルチタスク機能を持つ

図11●時分割によるマルチタスク
2つのプログラムを切り替えながら実行する。ユーザーからは2つのプログラムが同時に実行されているように見える
 マルチタスクとは,複数のプログラムを同時に実行する機能である。Windowsは,時分割とメッセージの2つの方法でマルチタスクを実現している。時分割によるマルチタスクが本当のマルチタスクであり,メッセージによるマルチタスクは,見かけだけの疑似マルチタスクに過ぎない。

 時分割とは,短い時間間隔で,複数のプログラムを切り替えながら実行することである(図11[拡大表示])。これによって,ユーザーの目には,複数のプログラムが同時に実行されているように見える。OSが複数のプログラムの実行を制御する役割を担う。

 メッセージとは,ユーザーの操作やハードウエアの変化をOSからアプリケーションに知らせるものである。複数のプログラムを同時に起動し,そのウインドウをマウスで順番にクリックしていくと,それぞれのプログラムが順番に使用可能となる。ユーザーが使用していないプログラムは休んでいることになるが,ユーザーには複数のプログラムが同時に(実際には順番に)実行されているように見える(図12[拡大表示])。時分割によるマルチタスクは“本当の”マルチタスクと言えるが,メッセージによるマルチタスクは,見かけだけの疑似マルチタスクと言える。

図12●メッセージよるマルチタスク
ユーザーの操作(クリックなど)によって実行するプログラムを切り替える
 メッセージによるマルチタスクを利用するプログラムをコーディングする場合の注意点は,一度処理が始まったら何分も時間がかかるような処理を記述してはいけないということである。メッセージによるマルチタスクでは,ユーザーが使用していないプログラムは休んでいることを思い出してほしい。プログラマの立場から言えば,ユーザーが使用していないプログラムをうまく休ませる必要があるのだ。時分割によるマルチタスクを円滑に行うのはOSの責任であるが,メッセージによるマルチタスクを円滑に行うのはプログラマの役割なのである。

ネットワークやデータベースの機能を持つ

 Windowsにはネットワーク機能が標準で装備されているが,データベース機能は後から別途追加するようになっている。ネットワーク機能やデータベース機能は,OS本体に不可欠の機能ではないが,アプリケーションというよりはOSに近いものなので「ミドルウエア」と総称される。従って,パソコンで動作するプログラムの種類は,OS,ミドルウエア,およびアプリケーションの3種類に大別されることになる。

図13●アプリケーションは,OSとミドルウエアを利用して動作する
 アプリケーションは,OSとミドルウエアの機能を利用しながら動作することになる。OSとミドルウエアをまとめてシステム・ソフトウエアとも呼ぶ(図13[拡大表示])。

 OSは一度インストールしてしまうと,他のものと簡単に交換できるものではないが,ミドルウエアは必要に応じて自由に交換できるという特徴がある。ネットワークのプロトコルを変更したり,データベースの種類を変更することができるのだ。ただし,ミドルウエアの変更によって,アプリケーションを改造することになる場合が多いので,ミドルウエアの選択には注意が必要だ。Windowsでは,ミドルウエアの機能をCOMとして公開することで,異なるミドルウエアを統一的に扱えることを目指している*4

プラグ&プレイによるドライバの自動設定

 プラグ&プレイは,新しい装置を挿入(プラグ)すると,すぐに使える(プレイ)という機能のことである。より具体的に言えば,新しい装置を挿入することで,その装置のハードウエアを制御するための「デバイス・ドライバ」と呼ばれるプログラムのインストールと,各種パラメータの設定が自動的に実行されるということである。

 デバイス・ドライバは,OSの機能の一部であり,ハードウエアとの基本的な入出力を行う機能を提供するものだ。キーボード,マウス,ディスプレイ,およびディスク装置など,一般的なコンピュータに必ず装備されているハードウエアのためのデバイス・ドライバは,OSと一緒にインストールされている。NICやSCSIインタフェースなどのハードウエアを後から追加した場合には,それぞれ専用のデバイス・ドライバをOSに追加することになる。新しいハードウエアを購入すると,フロッピ・ディスクやCD-ROMが同梱されていることがあるが,その中にはデバイス・ドライバが収録されている。

 OSは,新しいハードウエアの機能をシステム・コールとして提供する。デバイス・ドライバは,システム・コールの実体である関数やサブルーチンの集合体である。アプリケーションのプログラマは,システム・コールまたは高水準言語の関数を呼び出すことで,新しいハードウエアを使うことができるようになる。

 プログラマとして注意しなければならないのは,プログラム・コードとしては何ら問題なくても,デバイス・ドライバの機能によって正しい結果が得られない場合があるということだ。

デバイス・ドライバに合わせるしかない

図14●文字列を印刷するプログラム
 プリンタのデバイス・ドライバを例にして,実例を示そう。文字列を印刷するプログラムをVisual Basicで作成してみる(図14[拡大表示])。文字列の印刷位置を(0, 0)に設定して,「こんにちは」という文字列を印刷するだけのプログラムである。プリンタには様々な機種があるが,Windowsではデバイス・ドライバがプリンタの機種の違いを吸収し,同じシステム・コールで印刷を実現できるようにしてくれる。

 このプログラムを実行すると,あるプリンタでは用紙の左上ギリギリの位置から印刷が始まり,他のプリンタでは上と左に5mm程度の余白を置いてから印刷することもあるだろう。これは,プログラムが悪いのではなく,プリンタを実際に制御するデバイス・ドライバにとって(0, 0)位置が異なるからである。「こんにちは」という短い文字列を印刷するプログラム程度なら,何ら問題がないかもしれないが,プリンタ用紙を目一杯埋め尽くす印刷データは,他の機種のプリンタでは正しく印刷されない可能性もある。

 さらに注意しなければいけないのは,デバイス・ドライバのバージョンである。同じ機種のプリンタであっても,デバイス・ドライバがバージョン・アップされていて,機能が異なる場合がある。Windows 95/98とWindows NT用のデバイス・ドライバが異なる場合もある。同じ機種のプリンタであっても,デバイス・ドライバのバージョンが異なれば,違う機種のプリンタを使っているようなものだ。

 この問題を回避するためには,プログラムの動作環境を規定するしかない。プログラマは,作成したアプリケーションが,どのバージョンのWindowsで動作し,何と言う機種のプリンタの何と言うバージョンのプリンタ・ドライバで動作するかまで,ユーザーに知らせる必要があるのだ。

おわりに

 3回の連載で,プログラムが動作する仕組みを説明してきた。現在のプログラミング環境は,実に恵まれているものだといえる。高機能な開発ツールを使って,楽してプログラミングができるからだ。楽をするということは,効率的にプログラミングしていることなのだから,決して悪いことではない。

 ただし,もしも自分の思い通りにプログラムが動作しなかったときには,これまでの連載で解説してきた“プログラムが動作する仕組み”を振り返って,動作しない原因を考えてみてほしい。きっと,解決の糸口を見つけることができるだろう。