Version 15.16
クラスをエクスポートする!
「前回は関数をエクスポートするときの方法と装飾名の関係について説明し
ました」
『 __declspec(dllexport) を使うとエクスポート名がへんてこになるけど
仕方ない、って話だったね』
「だから、プラグインみたいに〈関数名を指定する〉場合はモジュール定義
ファイルを使って、それ以外は __declspec(dllexport) を使う、というの
が基本かな」
『そうなっちゃうんだね。あの装飾名はなんかちょっとヤだけど……』
「さて、今回は関数ではなくクラスをエクスポートします」
『クラスを!? なんか難しそう……』
「実はそんなに難しくないんです。まずは実際に使ってみましょう。
DLLTestEasy プロジェクトの DLLTestEasy.cpp を次のように修正してくだ
さい」
// DLLTestEasy.cpp
#include "stdafx.h"
#include "DLLTestEasy.h"
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
// これはエクスポートされた変数の例です。
DLLTESTEASY_API int nDLLTestEasy=0;
// これはエクスポートされた関数の例です。
DLLTESTEASY_API int fnDLLTestEasy(void)
{
OutputDebugString( "fnDLLTestEasy()\n" );
return 42;
}
// これはエクスポートされたクラスのコンストラクタです。
// クラスの定義については DLLTestEasy.h を参照してください。
CDLLTestEasy::CDLLTestEasy()
{
OutputDebugString( "CDLLTestEasy::CDLLTestEasy()\n" );
}
「修正箇所は、 CDLLTestEasy::CDLLTestEasy() の中に」
OutputDebugString( "CDLLTestEasy::CDLLTestEasy()\n" );
「を追加したこと。あと、前回の fnDLLTestEasy() の前の DLLTESTEASY_API
を元に戻したりしています。同じく」
// DLLTestEasy.h
// 以下の(略)
#ifdef DLLTESTEASY_EXPORTS
#define DLLTESTEASY_API __declspec(dllexport)
#else
#define DLLTESTEASY_API __declspec(dllimport)
#endif
// このクラスは DLLTestEasy.dll からエクスポートされます
class DLLTESTEASY_API CDLLTestEasy {
public:
CDLLTestEasy(void);
// TODO: この位置にメソッドを追加してください。
};
extern DLLTESTEASY_API int nDLLTestEasy;
DLLTESTEASY_API int fnDLLTestEasy(void);
「こちらは fnDLLTestEasy() の前に DLLTESTEASY_API を点け直しただけ。
ようするに、前々回の状態に戻しておいてもらえればOK」
『定義ファイル使わないようにってことね』
「あ、でも、別に今回は fnDLLTestEasy() は使わないから、前回のままで
もいいんだけどね。コンパイルエラーさえ出なければ大丈夫」
『組み合わせて使ってもいいんだ』
「気になる人は、モジュール定義ファイルを無効にしておいてください。
【FileView】の【DLLTestEasy.def】で右クリックして【設定】を選んで、
右側の【一般】ページの【このファイルをビルドしない】にチェックを
入れればエクスポートに使われないから」
『あれ? これって前に見たような……』
「 Version 15.02 ( No.302 ) でやったね」
『そか、ソースファイルをコンパイルしない方法だ』
「モジュール定義ファイルはソースファイルじゃないけど、同じように無効
化できるっていうこと」
『ふーん』
「さて、 DLL 側はこれで準備ができました」
『え、もう!? だってエクスポートの指定とかしてなくない?』
「してあるんです。 fnDLLTestEasy() の時もそうだったけど、 AppWizard
が CDLLTestEasy のエクスポート例をすでに作ってくれてるんです。まず」
// DLLTestEasy.h
// このクラスは DLLTestEasy.dll からエクスポートされます
class DLLTESTEASY_API CDLLTestEasy {
public:
CDLLTestEasy(void);
// TODO: この位置にメソッドを追加してください。
};
『あ! DLLTESTEASY_API って __declspec(dllexport) に置き換える
マクロだ!』
「そう、クラスのエクスポートをする時にも __declspec(dllexport) を使
うんです。クラスの場合、 class の直後に置けばOK」
『関数と似てる……』
「でも、メンバ関数には付けなくていいんです」
『本当だ。メンバ関数ひとつひとつに付けてない』
「これは、メンバ関数の定義の方も同じ」
// DLLTestEasy.cpp
// これはエクスポートされたクラスのコンストラクタです。
// クラスの定義については DLLTestEasy.h を参照してください。
CDLLTestEasy::CDLLTestEasy()
{
OutputDebugString( "CDLLTestEasy::CDLLTestEasy()\n" );
}
『ホントだ、メンバ関数の方についてない……これってすごく楽じゃな
い?』
「楽だよ。クラスのエクスポートは関数に比べて簡単なんです」
『へー』
「では、実際にこのクラスを使ってみます。ビルドして DLLTestEasy.dll
ができたら BuildTest\Debug フォルダにコピーして」
『ほい』
「 BuildTest プロジェクトの方で、 Version 15.09 ( No.309 ) と
Version 15.10 ( No.310 ) で fnDLLTestEasy() を使ったときと同じように
ヘッダーファイルとライブラリファイルを参照するようにして」
『前からなってなくない?』
「色々とごちゃごちゃ設定変えてるからね。それができたら Main.cpp をこ
う書き換えてください」
// Main.cpp
#include <Windows.h>
#include "DLLTestEasy.h"
int WINAPI WinMain
( HINSTANCE p_hInstance
, HINSTANCE p_hPrevInstance
, LPSTR p_pchCmdLine
, int p_iCmdShow
)
{
CDLLTestEasy cDLLTestEasy;
return 0;
}
『お、 CDLLTestEasy クラス使ってる! あれ、でもメンバ関数呼び出して
ないよ』
「うん、今回の例のこのメンバ関数」
// DLLTestEasy.cpp
// これはエクスポートされたクラスのコンストラクタです。
// クラスの定義については DLLTestEasy.h を参照してください。
CDLLTestEasy::CDLLTestEasy()
{
OutputDebugString( "CDLLTestEasy::CDLLTestEasy()\n" );
}
「コンストラクタだから」
『あ、よく見たら……だから作るだけで呼び出されるわけね』
「そういうこと。では試してみて」
『ほい。ビルドして実行……お、〈CDLLTestEasy::CDLLTestEasy()〉って出
た!』
「こんな感じに、関数と同じようにクラスも使えるわけです」
『それも、 class の後ろに DLLTESTEASY_API を付ければいいだけ……あ、
質問!』
「はい火美ちゃん」
『エクスポートすると、やっぱり変な装飾名になっちゃうの?』
「なります」
『モジュール定義ファイル使えばならない?』
「ううん、クラスのメンバ関数は複雑だから、モジュール定義ファイルは使
えないんです」
『げ! それってもしかして、プラグインみたいにできないってこと!?』
「そういうこと。そもそも、メンバ関数単独では呼び出せないでしょ」
『そっか、クラス作って、その変数通して呼ばなきゃいけないから……』
「一応、クラスでもプラグインみたいに使うことができるんだけど、すごく
難しいからそれはずっと先に」
『はーい』
/*
Preview Next Story!
*/
『これで関数もクラスもやったね』
「難しかった? 簡単?」
『んー、ひとつひとつは簡単だったけど、全体だと……』
「というわけで全部振り返ってみましょう」
『げ』
「というわけで次回」
< Version 15.17 一から DLL を作ってみる >
『につづく!』
「一から作ってみると思いの外難しいんだよね」
『それをしろと……』