【第9回】DLLの作り方と使い方
DLLとは?
ライブラリとは?
ゲーム、その他ソフトウェアを作成するには非常に多くの機能を実装しなければなりませんが、その中でも「文字を表示する」「音を再生する」「文字の入力を受け付ける」など多くの人が必ず欲しいと思うであろう機能が存在します。
ですが、ソフトウェアを作成するたびに機能を作るのは面倒ですし、なにより作業時間の無駄です。
そこでそのような機能を一つにまとめてしまいます。これをライブラリと呼びます。
DLLって何だ?
DLLとは、DynamincLinkLibraryの略でプログラム実行時にリンクされるライブラリのことです。
プログラム実行時にリンクするため、普通ライブラリは実行ファイルとは別のファイルとして保管されています。
Windowsであれば.dll
という拡張子がついているはずです。
DLLにすると?
先ほども解説した通りライブラリを別のファイルとして保管するため、実行可能形式のプログラムのサイズを小さくすることが出来ますし、ライブラリだけ入れ替えるといったことも可能です。
しかし、DLLのバージョンアップによってDLLを使用しているプログラムが突然動かなくなってしまうといった欠点も存在します。
実は、次の節以降で解説しているのは動的ロードの方法であり動的リンクの方法ではありません。
動的リンクとは、プログラムが実行されたときにリンクする方式です。
動的ロードとは、プログラムが任意にライブラリをロードしたときにリンクする方式を指します。
どちらもプログラム実行以降にリンクするという点では共通していますが、動的リンクでは実行時にリンクしているのに対し動的ロードではプログラム実行後、任意のタイミングでリンクしています。
似ているので混同しないように注意してください。
DLLの作成方法
DLLプロジェクトを新規作成する
プロジェクトを新規作成する画面を開き、下の画像を参考にしてダイナミック リンク ライブラリ(DLL)
を選択しOKを押します。
DLLの内容を作成する
以下の内容のmain.cpp
,main.h
を新規作成したプロジェクトの中に追加します。
main.cpp
#include "stdafx.h" #include "main.h" #include <iostream> DLLEXPORT int addNum(int a, int b) { return a + b; }
main.h
#pragma once #define DLLEXPORT extern "C" __declspec(dllexport) DLLEXPORT int addNum(int a, int b);
ライブラリを使う人に関数を公開するには、関数の頭にextern "C" __declspec(dllexport)
を付けます。(DLLの内部で使用する関数であれば付ける必要はありません。)
今回は入力する手間を省くために、#define
を使ってDLLEXPORT
と入力しても同じになるようにしています。(DLLEXPORT int~
は、extern "C" __declspec(dllexport) int~
と同じ。)
DLLを作成する
プロジェクトをビルドすると、DLLを作成することが出来ます。
DLL開発中はDebug構成にしてビルドしますが、本番用のDLLを出力する場合はRelease構成にしてビルドしてください。
今回はRelease構成でビルドしてください。
テスト用のプロジェクトを新たに作成する
DLLプロジェクトが置かれているソリューションに「Windows コンソール アプリケーション」という種類のプロジェクトを新たに作成してください。
詳しいプロジェクト作成の方法については、第6回をご覧ください。
コードを入力する
以下の内容のConsoleApplication1.cpp
を新規作成したプロジェクトの中に追加します。
ConsoleApplication1.cpp
#include "pch.h" #include <iostream> #include <windows.h> int main(void) { HINSTANCE hDLL; int(*addNum)(int, int);//関数addNumへのポインタ int ans = 0; hDLL = LoadLibrary(L".././Release/main.dll");//文字列の先頭に`L`を付けないとコンパイルエラーが発生する if (hDLL == NULL) { std::cout << "main.dll is missing." << std::endl; } else if ((addNum = (int(*)(int, int))GetProcAddress(hDLL, "addNum")) == NULL) { std::cout << "GetProcAddress is failed" << std::endl; } else { ans = addNum(2, 3); std::cout << ans << std::endl; FreeLibrary(hDLL); } return 0; }
LoadLibrary
関数で前の節で作成したmain.dll
を読み込む処理を行っています。(引数の文字列の先頭にLを付けないとコンパイルエラーになってしまいます。)
また、GetProcAddress
で関数addNum
へのアドレスを取得しelse
の部分で実際に呼び出しています。(ans = addNum(2,3)
)
LoadLibrary
,GetProcAddress
関数共に処理に失敗するとNULL
を返すためそれを利用してif-else if
ではエラー処理を行っています。
関数を呼び出した後はFreeLibrary
関数を実行して確保したメモリ領域を解放する必要があります。
プロジェクトをビルドして実行してみる
本プロジェクトをビルドし、Ctrl+F5
を押して実行してみましょう。
5
とコンソール画面に表示されていれば、作成したDLLを正しく呼び出せています。
上の手順に従ってプロジェクトを実行しても、上のようなエラーが出て実行できない場合があります。
これは、「Windows コンソール アプリケーション」のプロジェクトではなく「ダイナミック リンク ライブラリ(DLL)」のプロジェクトを実行しようとしていることが原因です。
第6回を参考にして、「スタートアッププロジェクト」を「Windows コンソール アプリケーション」のプロジェクトに変更してください。
次回予告
次回はスタティックリンクライブラリの作成方法について解説します。
7/18更新予定です。