DLLを作ってみる

DLLの作成はちょっと面倒くさい。
けど、なんか、決まった操作でとりあえずは作成できるようだ。

いつものごとく参考先の資料を流用&加筆で。

このドキュメントを書いている時点では、まだ、DLLを本格的に作っていないので、 後日加筆、修正すると思われます。

簡単なDLLの作成

関数のみのDLLはこの方法で良いかと。
(この時点では本格的にDLLを作成していないので、あくまで予想)

まずは[新規作成]→[プロジェクトタブ]→[MFC AppWizard(dll)]を選択。
プロジェクト名は適当に。(ここでは Test_DLL としましょう)
ウィザードが起動したら、[MFCの拡張DLL(MFCの共有DLLを使用)]にチェックを入れます。
そして[終了]ボタンを押しましょう。

[新規作成]→[ファイルタブ]→[C++ソースファイル]を選択。
ファイル名は TestMsg.cppとします。

同じようにヘッダーファイルを作成します。
[新規作成]→[ファイルタブ]→[C/C++ヘッダーファイル]を選択。
ファイル名は TestMsg.hとします。

まず、ヘッダーファイルにDLL,関数の宣言を記述します。

    #ifndef __TESTMSG__
    #define __TESTMSG__

    int WINAPI Dll_TestMessageBox();

    #endif

という具合に。
#ifdefでは、こヘッダファイルを多重読みこみさせないようにする宣言です。
#ifdef〜#endifの間に、関数の宣言等を記述することで、関数の多重宣言等を回避します(たしか)
int WINAPI Dll_TestMessageBox();
は関数のプロトタイプ宣言をしています。
関数名の前のWINAPIはAPIの宣言を意味します。
WINAPIを記述することで、API エントリ ポイントをエクスポートできます(よくわからんが)
まぁ、DLLで関数を宣言し、その関数をDLLの外部から参照させたい場合はWINAPIをつければ
良いのでしょう。きっと。

次にソースファイルに、実行部分を記述します。

    #include "StdAfx.h"
    #include "TestMsg.h"

    int WINAPI Dll_TestMessageBox()
    {
        return AfxMessageBox("このメッセージボックスはDLL内の関数から呼び出されています");
    }

最初の #include 部分はよくわかりません。
必要らしいので記述しておきましょう。
次の #include 部分は、先に記述したヘッダファイルです。
これがないと、その下で記述している関数が有効になりません。
というか、コンパイルできません。
上記の #include 文の下に、実際の関数が記述されています。

最後に、 Test_DLL.def を開いて、このファイルを修正します。
このファイルのEXPORTS部分に外部から参照させたい関数等を記述します。

EXPORTS
    ; 明示的なエクスポートはここへ記述できます
    Dll_TestMessageBox  @1

という具合に。
これで、コンパイルすればDLLは完成です。

では実際にこのDLLを利用します。

[新規作成]→[プロジェクトタブ]→[MFC AppWizard(exe)]を選択。
プロジェクト名は適当に。(ここでは Test_EXE としましょう)
とりあえずお手軽なダイアログ形式で作成しましょう。

さて、必要なファイルをTest_DLLの方からコピーします。
TestMsg.hをTest_EXEへ
Test_DLL.lib,Test_DLL.dllをTest_EXE\Debugへ
Debugフォルダが無い場合は、一度Test_EXEをコンパイルしてからコピーしましょう。

作成すると、ダイアログの編集画面が表示されると思います。
(表示されない場合は、リソースから開きましょう。)
とりあえず一つボタンを貼り付けて、ClassWizardで貼り付けたボタンのBN_CLICKED
関連する関数を追加してください。

Test_EXEDlg.cppFileViewから開いて、TestMsg.hをインクルードします。
BN_CKICKEDに関連づけられた関数に(OnButton1()と思います)下記のコードを入力

Dll_TestMessageBox();

この関数は、DLLで宣言している関数です。

最後に。[プロジェクト]→[設定]→[リンクタブ]→[オブジェクト/ライブラリ モジュール]に
Test_DLLで生成されたTest_DLL.libを記述する。
記述方法は Debug/Test_DLL.lib

これでコンパイルすれば実行できるはずです。

クラスを含むDLLの作成

まずは[新規作成]→[プロジェクトタブ]→[MFC AppWizard(dll)]を選択。
プロジェクト名は適当に。(ここでは Class_DLL としましょう)
ウィザードが起動したら、[MFCの拡張DLL(MFCの共有DLLを使用)]にチェックを入れます。
そして[終了]ボタンを押しましょう。

今回は、ダイアログクラスを利用したいので、リソースでダイアログを追加しておきます。
そして、クラスを新規作成します。
クラス名は適当に(ここでは CClassDlg とします)つけ、基本クラスは CDialog を利用します。
ダイアログIDは先ほどリソースで追加したダイアログのIDを指定してください。

作成したクラスのヘッダを修正します。
まず、 resource.h をインクルードします。
これは、現在のリソースを利用するためです。
これを忘れると、DLLを利用しているアプリケーションのリソースを参照することになるそうです。

次に ヘッダのクラス宣言部分を修正します。
class CClassDialog

class AFX_EXT_CLASS CClassDialog
に修正します。
AFX_EXT_CLASSはマクロで、このマクロを利用したクラスをエクスポートします。
このマクロを利用することにより、DLLを利用するアプリケーションから、クラスを利用することが 可能になるようです。

あと、ClassDlg.cppに

#include "	\ add additional includes here"

という文があります。これはコメントアウトしておきましょう。
(よくわからないので・・・爆)

コンパイルすればDLLの完成です。

つぎに作成したDLLを利用してみましょう。
まずは[新規作成]→[プロジェクトタブ]→[MFC AppWizard(exe)]を選択し、 ダイアログベースのプロジェクトを作成します。
ダイアログにボタンを貼り付けて、BN_CKICKEDメッセージを受け取る関数をClassWizardで作成します。

必要なファイルをコピーします。
Class_DLL.lib,Class_DLL.dllをTest_EXE\Debugへ
Debugフォルダが無い場合は、一度Class_EXEをコンパイルしてからコピーしましょう。

ClassDlg.hをClass_EXEDlg.cppにインクルードします。
今回はコピーしていないので直接パスを指定します。
#include "..\Class_Dll\ClassDlg.h"

BN_CKICKEDに関連づけられた関数に(OnButton1()と思います)下記のコードを入力
    CClassDlg dlg;
    dlg.DoModal();
最後に。[プロジェクト]→[設定]→[リンクタブ]→[オブジェクト/ライブラリ モジュール]に Class_DLLで生成されたClass_DLL.libを記述する。
記述方法は Debug/Class_DLL.lib

これでコンパイル、実行すれば完成です。

参考資料

VC++ 小手先のテクニック集 contents