#pragma twice

KAB-studio > プログラミング > #pragma twice > 316 Version 15.16 クラスをエクスポートする!

#pragma twice 316 Version 15.16 クラスをエクスポートする!

前のページへ 表紙・目次へ 次のページへ

 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 を作ってみる >
につづく!
一から作ってみると思いの外難しいんだよね
それをしろと……
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。