はじめに
プログラミングを学習していると、「ライブラリ」や「DLL」という言葉を耳にする機会が増えてきます。「何か便利な部品が入っている箱」のようなイメージはあるけれど、実際に自分で作ったことがある人は意外と少ないのではないでしょうか?
「DLLなんて上級者が作るものでしょ?」と敬遠してしまうのは非常にもったいないです。実は、DLLを自作できるようになると、複数のプログラムでコードを共有したり、メインのプログラムを書き換えずに機能だけをアップデートしたりといった、非常に柔軟な開発ができるようになります。この記事では、Visual Studioを使ったDLLの作り方から、実際にそれを呼び出して使う手順までを、一から丁寧に解説していきます。
DLLとは何か
DLLは「Dynamic Link Library」の略です。直訳すると「動的にリンクされる図書館」となりますね。これだけだと少しイメージしにくいかもしれません。
通常、プログラム(EXEファイル)を作るとき、すべてのプログラムコードを一つのファイルにまとめてしまう方法(静的リンク)があります。これは、旅行に行くときに家の家財道具をすべて背負っていくようなものです。
これに対しDLLは、「必要な機能を別のファイル(部品)に分けておき、プログラム実行時に必要なときだけ呼び出して使う」という仕組みです。つまり、旅行先で必要なものだけを現地レンタルするようなイメージに近いですね。これにより、EXEファイルのサイズを小さくしたり、修正があった場合にそのDLLファイルだけを差し替えれば済むという大きなメリットが生まれます。
関数との違い
よく「関数と何が違うの?」という疑問を持たれる方がいます。結論から言うと、DLLは「関数の入れ物(パッケージ)」です。
関数とは、プログラムの中で「足し算をする」「画面に文字を出す」といった処理の最小単位です。普段書いているソースコードの中にある関数は、ビルドするとEXEファイルの中に埋め込まれます。一方で、それらの関数を切り出して、「他のプログラムからも使えるように独立したファイル」にしたものがDLLです。中身は関数の集まりですが、その提供のされ方が違うと理解すればよいでしょう。

環境構築
今回は、Windowsでの開発において最も標準的な統合開発環境である「Visual Studio」を使用します。まだインストールしていない方は、Microsoftの公式サイトから無料版である「Visual Studio Community」をダウンロードしましょう。
「ダウンロード」を押して、セットアップを行いましょう。
インストーラーを起動したら、「C++によるデスクトップ開発」というワークロードにチェックを入れてインストールしてください。これだけで必要なコンパイラやツール類が一通り揃います。

プロジェクトの作成
Visual Studioを起動したら、「新しいプロジェクトの作成」を選択します。検索バーに「DLL」と入力すると、「ダイナミック リンク ライブラリ (DLL)」という項目が出てくるはずです(言語がC++になっていることを確認してください)。

これを選択して「次へ」進み、プロジェクト名(今回はMyMathDLLとします)を入力して「作成」をクリックします。すると、DLLを作るためのひな形コードが生成された状態でエディタが立ち上がります。

サンプルプログラム
それでは、実際に動くコードを書いてみましょう。今回はシンプルに「2つの整数の足し算」と「引き算」を行う関数を持つDLLを作成します。
まず、ヘッダーファイル(MyMathDLL.h)を新規作成ましょう。画面右側にある「ソリューションエクスプローラー」より「ヘッダーファイル」を右クリックし、追加より「新しい項目」を選択しましょう:

MyMathDLL.hという名前で新規に項目を作成します:

続いて、外部からこの関数を使えるようにするための「おまじない」を記述します。ここで重要なのが__declspec(dllexport)というキーワードです。これはコンパイラに対して「この関数はDLLの外に公開します」と宣言するためのものです。
#pragma once
#ifdef MYMATHDLL_EXPORTS
#define MYMATHDLL_API __declspec(dllexport)
#else
#define MYMATHDLL_API __declspec(dllimport)
#endif
extern "C" {
MYMATHDLL_API int Add(int a, int b);
MYMATHDLL_API int Subtract(int a, int b);
}
次に、ソースファイル(MyMathDLL.cpp)に関数の実体を書きます。同様に、「ソースファイル」を右クリックして項目を追加しましょう:

ファイルの名前をMyMathDLL.cppとします。内容は以下:
#include "pch.h" // プリコンパイル済みヘッダーが必要な場合
#include "MyMathDLL.h"
int Add(int a, int b) {
return a + b;
}
int Subtract(int a, int b) {
return a - b;
}
ビルド
コードが書けたら、いよいよビルドしてDLLファイルを生成します。画面上部のメニューから「ビルド」→「ソリューションのビルド」を選択してください。

エラーがなく正常に終了すると、プロジェクトフォルダ内のx64/Debug(設定によって変わります)フォルダの中に、以下のファイルが生成されているはずです:
この2つが生成されていれば、DLLの作成自体は成功です!

dllの呼び出し方
作ったDLLは、他のプログラムから呼び出して初めて意味を持ちます。確認のために、同じソリューション内に新しいコンソールアプリのプロジェクト(ClientAppとします)を追加してみましょう。
DLLを使う方法は大きく分けて2つありますが、今回は一般的な「暗黙的リンク」という方法を紹介します。手順は3ステップです。

呼び出し側のコードはこんな感じです:
#include <iostream>
#include "../MyMathDLL/MyMathDLL.h" // パスは環境に合わせて
int main() {
int result = Add(10, 20);
std::cout << "10 + 20 = " << result << std::endl;
return 0;
}
これを実行して、画面に「30」と表示されれば完璧です。

Pythonで呼び出す
また、このdllはPythonでも呼び出すことができます。それを可能にするライブラリが、ctypesというものです。以下は、このdllを呼び出す例です:
import ctypes
# DLLを読み込む
lib = ctypes.CDLL('./MyMathDLL.dll')
# 関数の引数と戻り値の型を指定
lib.Add.argtypes = [ctypes.c_int, ctypes.c_int]
lib.Add.restype = ctypes.c_int
# 実行する
result = lib.Add(10, 20)
print(f"計算結果: {result}")
このように、DLLを読み込んで関数の引数と返り値の型を指定し、実行することができます。実際に上記を実行すると以下のような結果が得られるでしょう:

おわり
DLLの作成は、最初は「__declspec」などの見慣れないキーワードが出てきたり、パスの設定が複雑だったりと難しく感じるかもしれません。しかし、一度その仕組みを理解してしまえば、巨大なプログラムを機能ごとに分割して管理したり、自分が作った便利な機能を他の人に配布したりと、プログラミングの幅が一気に広がります。
まずは今回のような簡単な計算機能から始めて、徐々に複雑な機能を持ったDLL開発に挑戦してみるといいと思います。案外いろんなところで使えますよ。