VC++ LIB、DLLの作成と参照方法
目次
概要
ライブラリ
再利用可能なプログラム
ライブラリの種類
・スタティックリンクライブラリ
~.lib
静的。
コンパイル時にリンクされ、実行ファイル(exe)になる。
exeだけで実行できる反面、libの内容変更時は再リンク、再リリースが必要。
・ダイナミックリンクライブラリ
~.dll
動的。
実行ファイル(exe)から実行時に呼び出される。
exeだけでなく、dllのリリースも必要な反面、dllの内容変更時はdllの再リリースだけで済む。
コンパイル、リンク手順
ソースコード1
↓ ←(コンパイラ)
ネイティブコード(機械語)1
ソースコード2
↓ ←(コンパイラ)
ネイティブコード(機械語)1
ネイティブコード1+ネイティブコード2
↓ ←(リンカ)
実行ファイル(exe)
DLLにおけるリンク方法
・暗黙的リンク
.libファイル内にdllの関数情報を保持。
libファイル内に関数情報を出力するには、__declspec(dllexport) を関数に付ける。
リンカはこれを使用してリンクを行いDLLを生成する。
・明示的リンク
.defファイル内にdllの関数情報を保持。
リンカはこれを使用してリンクを行う。
libファイルは必要無い。
通常関数
スタティックリンクライブラリ(lib)
【呼び出し先】
※~.h
namespace NS_MyFunc
{
int fnPlus(int prm1, int prm2);
}
※~.cpp
#include "MyFunc.h"
namespace NS_MyFunc
{
int fnPlus(int prm1, int prm2)
{
return prm1 + prm2;
}
}
これにより~.libファイルが作成される。
【呼び出し元】
※~.cpp
#include "MyFunc.h"
// ライブラリ参照先をソースで指定する場合
#pragma comment( lib, "~.lib" );
using namespace NS_MyFunc;
int _tmain(int argc, _TCHAR* argv[])
{
int ret = fnPlus(5, 5);
→ret:10
return 0;
}
(1)ヘッダーファイルの参照(インクルードディレクトリ、インクルードファイルの指定)
(2)ライブラリの参照(ライブラリディレクトリの指定)
(3)ライブラリの参照(ライブラリファイルの指定)
が必要。
これにより~.libファイルを参照/利用できる。
暗黙的リンク(lib+dll)
【呼び出し先】
※~.h
__declspec(dllexport) int __stdcall fnPlus(int prm1, int prm2)
{
return prm1 + prm2;
};
※__declspec(dllexport)により関数情報がlibファイルに書き込まれる。
【呼び出し元】
※~.h
#pragma comment( lib, "MyFunc.lib" )
※libファイルの参照(dllも同階層に保存しておく事)
__declspec(dllexport) int __stdcall fnPlus(int prm1, int prm2);
またはヘッダーファイルのinclude
int _tmain(int argc, _TCHAR* argv[])
{
int ret = fnPlus(5, 10);
→ret:15
return 0;
}
明示的リンク(dll)
【呼び出し先】
※~.cpp
int __stdcall fnPlus(int prm1, int prm2)
{
return prm1 + prm2;
};
※MyFunc.def
LIBRARY MyFunc
EXPORTS
fnPlus
【呼び出し元】
※~.cpp
// 関数ポインタ
typedef int(__stdcall *p)(int prm1, int prm2);
// DLLのロード
HMODULE hModule = LoadLibrary(_T("MyFunc.dll"));
if (hModule == NULL)
{
printf("%s", "DLLのロードに失敗しました。");
return 0;
};
// 関数のアドレス取得
p func = (p)GetProcAddress(hModule, "fnPlus");
if (func == NULL)
{
printf("%s", "関数のアドレス取得に失敗しました。");
FreeLibrary(hModule);
return 0;
}
// 実行
int ret = func(5, 10);
FreeLibrary(hModule);
クラス
スタティックリンクライブラリ(lib)
【呼び出し先】
※~.cpp
namespace NS_MyClass
{
MyClass::MyClass(int prm1, int prm2)
{
this->myInt1 = prm1;
this->myInt2 = prm2;
}
int MyClass::fnPlus()
{
return this->myInt1 + this->myInt2;
}
}
【呼び出し元】
※~.cpp
#include "MyClass.h"
#pragma comment( lib, "MyClass.lib" )
using namespace NS_MyClass;
int _tmain(int argc, _TCHAR* argv[])
{
MyClass *m = new MyClass(5, 10);
int ret = m->fnPlus();
return 0;
}
暗黙的リンク(lib+dll)
【呼び出し先】
※~.h
namespace NS_MyClass
{
class MyClass
{
private:
int myInt1;
int myInt2;
public:
__declspec(dllexport) MyClass(int prm1, int prm2);
__declspec(dllexport)int __stdcall fnPlus();
※__declspec(dllexport)定義された関数はライブラリに公開される。
};
}
※~.cpp
#include "MyClass.h"
namespace NS_MyClass
{
MyClass::MyClass(int prm1, int prm2)
{
this->myInt1 = prm1;
this->myInt2 = prm2;
}
__declspec(dllexport)int __stdcall MyClass::fnPlus()
{
return this->myInt1 + this->myInt2;
}
}
構成の種類は「スタティックライブラリ」
「通常関数」参照
【呼び出し元】
#include "MyClass.h"
using namespace NS_MyClass;
int _tmain(int argc, _TCHAR* argv[])
{
MyClass *myClass = new MyClass(5, 5);
int ret = myClass->fnPlus();
→ret:10
return 0;
}
・ヘッダーファイル参照方法(インクルードディレクトリ)
・ライブラリ参照方法(ライブラリディレクトリ)
・リンカー入力指定(ライブラリファイル名)
は通常関数と同じ。
「通常関数」参照
明示的リンク(dll)
【呼び出し先】
※~.h
class MyClass
{
public:
クラス外から呼び出せるフレンド関数を定義
friend MyClass* CreateInstance();
friend void ReleseInstance(MyClass* p);
public:
メンバー関数は仮想関数でないとダメ(らしい)
virtual int __thiscall fnPlus(int prm1, int prm2);
};
// MyClassのインスタンス(のアドレス)を返す
MyClass* CreateInstance() {
return new MyClass;
}
// インスタンスを破棄
void ReleseInstance(MyClass* p) {
delete p;
}
int __thiscall MyClass::fnPlus(int prm1, int prm2)
{
return prm1 + prm2;
}
※MyClass.def
LIBRARY MyClass
EXPORTS
fnPlus
※これによりdefファイルの内容がdllに埋め込まれる。
【呼び出し元】
int _tmain(int argc, _TCHAR* argv[])
{
// DLLのロード
HMODULE hModule = LoadLibrary(_T("MyClass.dll"));
if (hModule == NULL)
{
FreeLibrary(hModule);
return 0;
}
// DLL内のCreateInstanceメソッドを取得
typedef MyClass* (__thiscall *CreateInstance_)();
CreateInstance_ c = (CreateInstance_)GetProcAddress(hModule, "CreateInstance");
if (c == NULL)
{
FreeLibrary(hModule);
return 0;
}
// DLL内のReleseInstanceメソッドを取得
typedef void(__thiscall *ReleseInstance_)(MyClass* p);
ReleseInstance_ r = (ReleseInstance_)GetProcAddress(hModule, "ReleseInstance");
if (r == NULL)
{
FreeLibrary(hModule);
return 0;
}
// CreateInstanceメソッドを実行し、MyClassクラスのインスタンスを作成
MyClass *m = c();
// メンバー関数を実行
int ret = m->fnPlus(5, 10);
// ReleseInstanceメソッドを実行し、MyClassクラスのインスタンスを破棄
r(m);
FreeLibrary(hModule);
return 0;
}
呼び出し規約
関数における引数の保存先等のルール
異なる言語の関数を呼ぶ場合、規約を合わせる必要がある。
__stdcall
WIN32 API規約
スタックの解放を呼ばれた側が行う。
__cdecl
C言語規約
スタックの解放を呼ぶ側が行う
__thiscall
C++メンバ関数規約
クラスのメンバ関数に使用
clrcall
.NET Framework専用規約