DLLプログラミングは、ウィンドウズプログラミングと切っても切れない関係……のはずなのに、結構わかりにくいんですよね。そういう部分をまとめてみました。
|
「DLL」は知ってるけど……
「DLL」。この名称は「Dynamic Link Library」の略です。日本語に訳すと「動的にリンクするライブラリ」といったところでしょうか<一語しか訳してないやん。
通常アプリケーションを作製する場合、「各ファイルをコンパイルする」−「作製されたオブジェクトファイルをリンクする」という手順(いわゆる「ビルド」と呼ばれるもの)を踏んで「実行ファイル(Exeファイル)」が作製されます。
このソースコードの一部を実行ファイルとは別に作製したものが、DLLです。
実行ファイルとDLLは、別々に作製されます。DLLも実行ファイルと同じ手順、コンパイルを行い、リンクをして、作製されます。実行ファイルも、ソースの一部がない状態で、コンパイルされ、リンクが行われて、作製されます。こうして、元はひとつだったファイルがふたつに分かれたことになります。 DLLへのリンクは、実行ファイルが「実行」された時に行われます。実行ファイルはまず実行ファイルのあるフォルダからDLLを探し、カレントフォルダからDLLを探し、システムフォルダからDLLを探し、ウィンドウズフォルダからDLLを探します。 DLLが見つかったら、実行ファイルはDLLへとリンクします。こうしてふたつのファイルはひとつの実行ファイルと同じ機能を持つことになるというわけです。このリンクを「動的(Dynamic)リンク」と呼びます。
このように、DLLとは「実行するときだけリンクされる、プログラムの一部」なのです。 |
DLLを使うメリットとデメリット
DLLを使うメリットとデメリットは、なんでしょうか。
メリットはまず「ファイルサイズの節約」でしょう。ある関数やクラスをいくつものアプリケーションで使う場合、その関数やクラスをDLLの中に入れてしまえば、単純計算で「DLLのサイズ×(アプリの数−1)」だけの節約になります。
メリットとデメリットが同時に存在するのが、「同じコードの省略」です。プログラムの中で似たコードをできるだけ作らないのが、バグを減らすコツのひとつです。これはアプリケーション単位の話ですが、DLLを用いればさらに複数のアプリケーション内の同一コードを省略して、ひとつにまとめることができることになります。
別に、「DLLに使うコードは元々多く存在しなければならない」ということはなく、たった一度しか使われないような希有なコードを入れることもあります。例えば、その希有なコードを組めるスタッフがいなくて、外注しなければならない場合、その完成品をDLLとして受け取ることで、実行ファイルとDLLを別プロジェクトとして平行作業することができます。
DLLは、システムフォルダにインストールされることで、そのDLLをすべてのアプリケーションが使用できるようになります。のちほど説明しますが、すべてのウィンドウズAPIは、DLL内の関数として提供されています。つまり、システムフォルダのDLLはそのままウィンドウズのシステムとなるということです。
それと、「システムフック」と「サブクラス化」という、ユーティリティアプリケーションにとって非常に強い味方となるこのふたつの機能を使用する場合、DLLを必ず使わなければならないのです。 |
「ライブラリファイル」のあるDLLを使ってみよう!!
さて、では実際にDLLをアプリケーションで使ってみましょう!! DLLを使う場合、「ライブラリファイル(拡張子がLibのファイル)」を使う場合と使わない場合で大きく違います。今回は使ってみましょう(使わない方法は次回説明します)。
今回サンプルとして使ってみるDLLおよびその中の関数を説明します。今回使用するのはsndPlaySound()という関数です。この関数はAPIに区分されますが、その中でも「マルチメディアAPI」と呼ばれるものです。マルチメディアAPIは、音を鳴らしたり、動画を表示したりといったまさに「マルチメディア」な機能を持ったAPIグループです。DirectXのようなばりばりの機能は持っていませんが、アプリケーションでちょっと何かしたいな、という時くらいには十分役立ちます。
まず、最初に「Win32SDKヘルプ」のsndPlaySound()のページを見てください。英語で色々書かれていますねー。そのページの一番上の行。関数名の右隣にみっつのボタンがありますね。その一番左の「Quick Info」のボタンを押してください。
Import Libraryは、プログラムを組むときに使う情報が入っている「ライブラリファイル」のファイル名です。これが、プログラムを組むときに必要になってきます。 |
ライブラリファイル
コンパイルが終了してObjファイルがいっぱいできた後、リンカは「このオブジェクトファイルが使ってる関数はどのオブジェクトファイルにあるのかなー」と調べます。その中から見つからないと、「ぐがっ、てことはDLLかぁ!?」と、今度は「ライブラリファイル」を検索します。 検索するライブラリファイルのリストは「プロジェクト」−「設定」ダイアログの「リンク」ページ・「一般」カテゴリ・「オブジェクト/ライブラリモジュール」の中に書かれているものです。え? 何もかかれてないって? さてはあなた、MFCプログラムしかしてませんね。早速、素の「Win32 Application」を作製して同じ欄を見てみましょう。kernel32.lib user32.lib gdi32.lib...とずらーっと書いてあるでしょう。MFCはちょっとした工夫で隠してあるだけです(この部分はのちほど説明)。
さて、見つからない関数があった場合、この「検索ライブラリファイルのリスト」の順に、ライブラリファイルを調べて「関数があるか」チェックします。
「ライブラリファイル」は、DLLの作成時に一緒に作製されるファイルです。DLLの中の「外から使われるための関数・クラス」は、特別に外から分かる形になってコンパイルされます(これを「エクスポート」といいます)。このとき、「作製されたDLLのファイル名(基本的にライブラリファイルの拡張子違い)」と「エクスポートされた関数・クラス」が、ライブラリファイルに書き込まれます。
「関数どこかなー」とリンカは、ライブラリファイルの中の関数を検索していきます。関数が見つかったら「この関数はこのDLLにあるよ」と書き込んで、検索を終了します。不明な関数がなくなったらリンクは終了、実行ファイルが完成します。
ここで重要なのは「DLLは必要ない!!」ということです。実行ファイルを作製するときに必要なのは「ライブラリファイル」です。これは逆に言えば「ライブラリファイルがすべて」ということです。ライブラリファイルが古いままだと、新しいDLLと合わなくてアプリケーションが実行できなくなります。リンカはライブラリファイルさえあれば安心してしまうのです。 |
で……使おうね
話が逸れちゃいました。例を元にちゃんと使ってみましょう。
sndPlaySound()のリファレンスを元に、ライブラリファイルとヘッダーファイルが分かりました。まず、ライブラリファイルを何とかしましょう。
VCのMFCのヘッダーファイル(たぶんVC/MFC/Include/フォルダ)の中のAFX.hの最初の方を見てください。#pragma comment(lib, "kernel32.lib")みたいなのがずらーっと書いてありますね。そして、中にはライブラリファイル名が……。そう、ここで検索ライブラリファイルリストを設定しているのです。
実際のコードは、stdafx.hの下の方(//{{AFX_INSERT_LOCATION}}の上の行くらい)に、次の2行を追加してください。 |
#pragma comment(lib, "winmm.lib")
#include <mmsystem.h>
ライブラリファイル名とヘッダーファイル名が「リファレンス」にあったものと同じだということを確認してください。こういう風に書き込めば、他で設定する必要はないということですね。
ちなみに話は逸れますが、「プロジェクト」−「設定」ダイアログの「C/C++」ページ・「プリコンパイル済みヘッダー」カテゴリで、「プリ(略)を使用」を選びかつ「StdAfx.h」を設定しているのなら、とてつもなく大きい「Pchファイル」が作製されるでしょう。
はっ、まだ残っていましたね、実際に音を鳴らす部分です。ま、ソースファイルのどこでもいいんで次の行を加えてください。 |
::sndPlaySound( "Test.wav", SND_ASYNC | SND_NODEFAULT ); //音発生!
んで、「Test.wav」というファイルをどっかから調達して、置いてください(置く場所ですが、デバッグバージョンだと「プロジェクトファイルのあるフォルダ」みたいです。心配の時はフルパスで指定してね)。
さて、実際にプログラム内でしたことはなんでしょう。まとめると、 |
APIの場合
先ほどちょっと書いた「Win32 Application」の場合を思い出してください(まだ見てない人は必ず試すこと!! もしくは「MFCユーザーのためのAPIプログラミング講座」のサンプルを見てね)。ライブラリファイルの検索リストにずらーっと書かれていましたね。 さて次に、RegisterClass()とかCreateDC()とかGlobalAlloc()の各APIのリファレンスを見てください。user32.lib、gdi32.lib、kernel32.libをそれぞれインポートすること、と書かれていますね。そして、それを上のWin32アプリで検索リストに加えてますね。またはMFCの場合にはAfx.hに#pragmaを使って加えられてますね。
そう、ちょっと触れたとおり、APIはすべてDLLに入っており、ライブラリファイルを使ってアプリケーションからリンクするという形をとっているのです。MFCを使っていると、「DLLなんて使ってないよーん」とか思うかもしれませんが、全然そういうことはないのです。ウィンドウズアプリケーションはすべて、こうしてDLLを通してAPIを使用し、アプリケーションが実行されるのです。 |
まとめ&これから
ちょっと触れたように、この講座は最終的には「システムフック」や「サブクラス化」を解説しようと思っています。また、次回は「DLLの実行時リンク」を紹介しようと思います。 「あれ? MFCチップスにおんなじのなかった?」ありました(爆)。まぁ図とか増やして、もうちょっと分かりやすくして、別講座にするってことです。あんまり気にしないでね。 |
(C)KAB-studio 1998 ALL RIGHTS RESERVED. |