#はじめに
Visual C++ ではクラスの DLL も簡単に作ることができます。しかし、関数の DLL と違ってクラスの DLL にはいろいろ制約があって、複雑で大きなクラスを DLL 化するのは簡単ではないようです。
クラスをエクスポート/インポートするには dllexport 属性または dllimport 属性をクラスに与えるだけでよいようですが、下記の MSDN の記事にいろいろ制約事項が書かれています。
次の Qiita の投稿も参考になります。
上記の投稿にも書いてありますが、クラスの DLL は制約が多く、大きく複雑な DLL だと制約を見落としがちです。結論から言うと、そういうクラスは DLL でなくスタティックライブラリにしたほうが無難なようです。
参照
* 関数のDLLについてはこちら
* スタティックライブラリについてはこちら
* MFC の DLL についてはこちら
#プロジェクトの作成
プロジェクトの作成ですが、特別なことは特になくて「新しいプロジェクト」ダイアログで「Windows デスクトップ」グループの中の「ダイナミックリンクライブラリ(DLL)」を選んで作成します。具体的には次の投稿を参照してください。
Visual Studio 2017 Visual C++ による Win32 DLL の開発
これによって作成されるプロジェクトは、一般的な DLL のひな形でヘッダーファイルも含まれません。ヘッダーファイルがないと、DLL を呼び出すときに不便なのでプロジェクトに追加しておきます。
クラスの先頭に dllexport 属性が必要です。以下では「C++形式の動的リンク・ライブラリの書き方(msvc編)」に倣って、次のようなマクロを使用します。
- dllのビルド時: #define DLL_EXPORT __declspec(dllexport)
- exeのビルド時: #define DLL_EXPORT __declspec(dllimport)
##サンプル DLL のソースファイル
// ClassDLL.cpp : DLL アプリケーション用にエクスポートされる関数を定義します。
//
#define DLL_EXPORT __declspec(dllexport)
#include "ClassDLL.h"
MyClass::MyClass() : m_Count(0)
{
}
LPCTSTR MyClass::get_Name()
{
return NAME;
}
int MyClass::get_Count()
{
return m_Count;
}
void MyClass::addCount()
{
m_Count++;
}
void MyClass::clearCount()
{
m_Count = 0;
}
##サンプル DLL のヘッダーファイル
この場合、stdafx.h は変更なしで構いません。
#pragma once
#include "stdafx.h"
class DLL_EXPORT MyClass
{
protected:
int m_Count;
public:
const LPCTSTR NAME = L"MyClass";
MyClass();
LPCTSTR get_Name();
int get_Count();
void addCount();
void clearCount();
};
ビルドを行い、ソリューションの下の Debug (または Release) の中に DLL と LIB ファイルができていることを確認します。
#サンプルのテストプログラム
呼び出し側ではマクロ DLL_EXPORT が __declspec(dllimport) になるようにします。これにより、クラスの宣言に付いた DLL_EXPORT が dllimport になります。
また、プロジェクトのプロパティダイアログを開き、「リンカー」「入力」「追加の依存ファイル」にインポートライブラリを追加しておきます。インポートライブラリは、ソリューションの下の Debug (または Release) の中にクラスのファイル名.lib というファイル名で作成されています。
// TestClassDLL.cpp : アプリケーションのエントリ ポイントを定義します。
//
#include "stdafx.h"
#define DLL_EXPORT __declspec(dllimport)
#include "ClassDLL.h"
int main()
{
MyClass obj;
wprintf_s(L"%s\n", obj.get_Name());
obj.addCount();
obj.addCount();
obj.addCount();
wprintf_s(L"%d\n", obj.get_Count());
obj.clearCount();
wprintf_s(L"%d\n", obj.get_Count());
getchar();
return 0;
}