Version 15.12
API も DLL !
「前回は DLL のエクスポートとインポートについて説明しました」
『関数をエクスポートするとライブラリファイルにその関数の情報が出力さ
れて、呼び出す方はインポートしてその情報を取り込んで、実行した時に
DLL を探してその関数を呼び出す、と』
「このあたりをもう少し理解するために、 API の呼び出しについて見てみ
ます」
『 API ? なんでいまさら API ?』
「 API も DLL だからね」
『え、そうなの?』
「そう、たとえば C:\WINNT\system32 フォルダにある kernel32.dll とか
user32.dll とかの DLL が API の入っている DLL です」
『へー、この中に入ってるんだ』
「たとえば、 API のひとつ、 MessageBox() 関数」
// Main.cpp
#include <Windows.h>
int WINAPI WinMain
( HINSTANCE p_hInstance
, HINSTANCE p_hPrevInstance
, LPSTR p_pchCmdLine
, int p_iCmdShow
)
{
MessageBox( NULL, "テスト", "テストダイアログ", MB_OK );
return 0;
}
「プロジェクトは BuildTest で試してください」
『フツーにダイアログ出すやつね』
「さて、この MessageBox() がどの DLL にあるか」
『え? それ調べる方法あるの?』
「 MSDN に書いてあります。 MSDN の MessageBox() のリファレンスを見て
みて」
MessageBox
(略)
対応情報
Windows NT: バージョン 3.1 以降
Windows: Windows 95 以降
Windows CE: バージョン 1.0 以降
ヘッダ : winuser.h 内で宣言
インポート ライブラリ : user32.lib を使用
「英語版はこう書いてあります」
QuickInfo
Windows NT: Requires version 3.1 or later.
Windows: Requires Windows 95 or later.
Windows CE: Requires version 1.0 or later.
Header: Declared in winuser.h.
Import Library: Use user32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows
and Windows NT.
「特に重要な所は【インポート ライブラリ】とか【Import Library】って
書いてあるところ」
『 user32.lib って書いてある、ライブラリファイルだ!』
「つまり MessageBox() は user32.lib に情報があって、 user32.dll に
エクスポートされてる、ってことです」
『これを見れば、ライブラリファイルと DLL が分かるってことなんだ。
……もしかしてそれって、こういうふうに書かれてないとわからないって
事?』
「基本的にはそういうこと。一応ライブラリファイルの中からエクスポート
された関数を抜き出す方法とかはあるけど、そういうのを調べない限りは分
からないから」
『不便ねー。自分でライブラリを作ってそれを他の人が使う場合とかは、そ
ういうドキュメントも用意しなきゃいけないってことなんでしょ?』
「そうなるんだよね。ちょっと面倒かも」
『……でも、これでライブラリファイルとか分かったわけだけど、実際にこ
れって使ってるの?』
「はい、問題。 DLLTestEasy.lib を使う際、このファイルをどこで指定し
たでしょう」
『 Version 15.09 ( No.309 ) でやったね、メニューの【プロジェクト】-
【設定】ダイアログの【リンク】タブの【一般】の
【オブジェクト/ライブラリ モジュール】に……あ!』
kernel32.lib
user32.lib
gdi32.lib
winspool.lib
comdlg32.lib
advapi32.lib
shell32.lib
ole32.lib
oleaut32.lib
uuid.lib
odbc32.lib
odbccp32.lib
DLLTestEasy.lib
『こんなにライブラリファイルが指定されてる! user32.lib もある!』
「ちなみに、これは AppWizard でプロジェクトを作ったときにセットして
くれてるデフォルトのライブラリファイル。だから、 API のリファレンス
を見て、使う必要がないライブラリファイルがあれば」
『削除していい、ってこと?』
「そう。実際に user32.lib だけで試してみて」
『うわ、怖い……あ、でもビルド通った。実行もできた』
「この辺は、 AppWizard がしてくれてるから普段は気にしないけど、必要
な API を元にライブラリファイルの指定をする、っていうのが本当の手順
かな」
『でもそれは難しそう……』
「ま、逆に言うと、とりあえずライブラリファイルを指定する、っていうの
も問題はないから」
『今まで問題なかったんだもんね』
「それと、 MFC の場合はちょっと違います」
『え、違うの?』
「 MFC を使うプロジェクトを開いてみて。この欄が」
『あ! 全然何も書かれてない!!』
「そう、 MFC の場合には、別の方法でライブラリファイルを指定している
んです」
『別の方法……もしかして、 Version 15.08 ( No.308 ) でやった
#pragma comment を使った方法のこと?』
「そう! Visual C++ のインストールフォルダが
C:\Program Files\Microsoft Visual Studio だとすると、その下の
VC98\MFC\Include に MFC のインクルードファイルのフォルダがあるんだけ
ど、その中に AFX.H ってファイルがあるでしょ」
『お、 afx って名前のヘッダーファイル』
「この中にこんなふうに書かれています」
#pragma comment(lib, "kernel32.lib")
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "gdi32.lib")
#pragma comment(lib, "comdlg32.lib")
#pragma comment(lib, "winspool.lib")
#pragma comment(lib, "advapi32.lib")
#pragma comment(lib, "shell32.lib")
#pragma comment(lib, "comctl32.lib")
『おおっ、 #pragma comment でライブラリファイルが指定されてる!!』
「 MFC のプロジェクトの場合は、 MFC のヘッダーファイルでこういう形で
ライブラリファイルを指定していて、そしてそのファイルを StdAfx.h で
インクルードしているから」
『設定ダイアログの方にはないわけねー』
「ここまでで重要なのは、 API も DLL を使っていること、そして、そうい
う DLL と、自分で作った DLL に大きな違いはないってこと」
『同じ DLL で、同じように作れるってことね』
「作れるのもそうだし、呼び出すのもそう。 DLL を使う、ってことに抵抗
があったかもしれないけど」
『気付いたら使ってた、だから気にするな?』
「まぁそういうことだね。 DLL を単純に使う時には、難しいこと考えなく
ていいから」
『……ちょっとマテ。それは、難しい場合があるってこと?』
「うん。 DLL の使用方法には、次の3つがあります」
・ DLL 内の関数を普通に呼び出す。
・ DLL 内の関数を動的に見つけて呼び出す。
・ DLL 内のクラスを使う。
「厳密に言うとこの3つは同列に並べちゃいけないんだけど、現実的には、
DLL の使い方はこの3つ」
『今まで使ってきた方法は?』
「一番上の」
・ DLL 内の関数を普通に呼び出す。
「です。次の」
・ DLL 内の関数を動的に見つけて呼び出す。
「は、 DLL 内の関数を特殊な方法で呼び出します」
『特殊な方法?』
「これは次回説明するからそれを見てもらった方がいいかな。最後の」
・ DLL 内のクラスを使う。
「これは、関数と同じ方法でクラスを使う方法。これは簡単なんだけど、一
応最後に説明します」
『そういえば、最初に AppWizard が作ってくれたソースの中にクラスあっ
たよね』
「あれを使えば簡単にできるけど、ちょっと遠回りして説明していくことに
します。というわけで、次回に続く!」
/*
Preview Next Story!
*/
『確かに DLL 使うだけなら簡単そうだけど、なんだか裏がありそう』
「あります」
『あからさまに!!』
「簡単に使えるけど、思わぬ所に落とし穴が」
『落とし穴嫌だー』
「というわけで次回」
< Version 15.13 DLL の実行中リンク >
『につづく!』
「じゃ、次回は落とし穴なしで」
『お』