記事で紹介したサンプル・プログラムをダウンロードできます
<Delphi0705.lzh><Delphi0705.zip>

 今回は,マウスカーソルの動きを記録するアプリケーション「MouseLogger」(以下,ML)を作成します(図1)。このアプリケーションの作成を通して,DLL,WindowsHook,メモリーマップドファイル,クラスの作成方法を紹介しましょう。

図1●今回作成するアプリケーション「MouseLogger」。マウスの軌跡を記録できる。(a)が操作画面。「軌跡を観る」ボタンを押すと,キャプチャしたマウスの軌跡を表示する。図の(b)はマインスイーパをプレイした様子
図1●今回作成するアプリケーション「MouseLogger」。マウスの軌跡を記録できる。(a)が操作画面。「軌跡を観る」ボタンを押すと,キャプチャしたマウスの軌跡を表示する。図の(b)はマインスイーパをプレイした様子

 まず最初に,DLL,WindowsHook,メモリーマップドファイルなどの,MLを構成する主要な技術を解説します。そのあとにサンプルの作成を通して,解説した技術の実際を見ていくことにします。

DLLは動的なライブラリ

 DLLの概要から解説を始めましょう。DLLはDynamic Link Libraryの略で,アプリケーション実行時に動的にリンクされるライブラリのことです。

 わざわざ“動的”と書いたところがポイントです。Delphiでのアプリケーション開発でよく使われるVCL(Visual Component Library)は,“静的な”ライブラリです。コンパイル時にリンクされて,プログラマが書いたコードと一体化してアプリケーションを構成します。本連載でこれまで作成してきたアプリケーションも,Turbo Delphiが生成したEXE形式の実行ファイル一つだけで動作しますね。

 一方,DLLを利用するアプリケーションの場合,EXEファイルとは別にプログラムを収めたファイルが存在します。このファイルを「DLLファイル」と呼びます。DLLを利用するアプリケーションは,DLLが含む機能を必要としたタイミングで,自分自身のEXEファイルとは別のDLLファイルにある関数を呼び出します。

 この仕組みにより,プログラムがよく利用する機能を一カ所にまとめておくことができます。使用頻度の高い関数をDLLとしてまとめておけば,アプリケーション本体のサイズを小さくできますね。

 すでにみなさんは,DLLの恩恵を多く受けています。代表的な使用例はOSです。ファイルシステムへのアクセスや,画面描画など,OSがプログラムに提供する機能は,複数のアプリケーションから利用されます。このため,OSの実装にはDLLがうってつけです。実際,VCLによってラッピングされている Win32API*1は,そのほぼすべてがDLLとして提供されています。

DLLの自動的なリンク

 Delphi言語は,言語レベルでDLLを読み込んで利用する機能を備えています。例で見てみましょう(リスト1)。ここではWin32APIが提供しているMessageBoxA*2というAPIをリンクしています。このコードの中でDLLをサポートする部分は,external指令*3以降です。

リスト1●MessageBoxAをリンクするコード
リスト1●MessageBoxAをリンクするコード

 external指令は,直前に定義されている関数がDLL内部の関数であることを宣言するものです。構文は,externalのすぐあとにDLLのファイル名を指定して,その後ろにname指令またはindex指令でDLL内の関数を指定する――というものです。リスト1で見てみると,ファイル名を「user32.dll」,関数を「MessageBoxA」と,それぞれ指定していることがわかります。

 このようにexternal指令を付けることを,external宣言といいます。external宣言された関数は,プログラム開始時に自動的にリンクされます。普通の関数宣言*4の後ろにexternal指令を付けるだけでよいので,非常に簡単ですね。

 しかし,この方法には弱点があります。指定したDLLファイルと,指定した関数がどちらも確実に存在するときにしか使用できない,というのがそれです。この方法でDLL内の関数を利用する場合,プログラム開始時に自動的にリンクしようとするためです。もし,存在しない関数をリンクしようとした場合,実行してすぐに図2のようなエラーになってしまいます。Windowsが提供するDLLには複数のバージョンがあります。そして,このバージョンに応じて,ある関数が存在したり,しなかったりする場合があります。

図2●存在しない関数をリンクしようとするとエラーになる
図2●存在しない関数をリンクしようとするとエラーになる

 このような場合に有用なWin32APIが,「LoadLibrary」と「GetProcAddress」の二つです。リスト2ではこの二つのAPI を利用して,リスト1と同様にMessageBoxAをリンクしています。external宣言より,ずいぶんコード量は増えてしまいます。その代わり, DLLファイルがあるか,DLL内に呼び出したい関数があるかをチェックできます。また,プログラムの任意の時点でDLLの関数を呼び出すことも可能です。今回の「ML」ではこの方法は使用しませんが,リスト2に示した二つのAPIを使用する機会はけっこう多いので,知っておいて損はありません。

リスト2●「LoadLibrary」と「GetProcAddress」を利用してMessageBoxを表示するコード
リスト2●「LoadLibrary」と「GetProcAddress」を利用してMessageBoxを表示するコード
[画像のクリックで拡大表示]