開発を行っていると、同じ処理を何度も書いていたり、機能を追加するたびに実行ファイルが大きくなるといった悩みが発生します。
動的リンクライブラリという仕組みを使用することにより、共通の機能をひとつのファイルにまとめ、複数のプロジェクトで同じコードを呼び出すことが可能となります。
本記事では動的リンクライブラリの作成方法とサンプルコードを紹介します。
動的リンクライブラリ/Dynamic Link Libraryとは
動的リンクライブラリとは、プログラムの一部機能を外部ファイルとして分離し、必要なときに呼び出すことができる仕組みのことです。
静的なライブラリとは異なり実行時にリンクを行うため、ビルドしたexeのサイズが小さくなる傾向があり、ライブラリの更新時にもアプリケーションの再ビルドが必要ではないため、ライブラリの差し替えのみでよいといったメリットがあります。
その反面、デバッグが難解になったり、バージョンの問題が起こりやすいといったデメリットも存在します。
一般的に英語名のDynamic Link Libraryの頭文字を取ってDLLと略されます。
以降本記事では動的リンクライブラリのことをDLLと呼ぶこととします。
想定環境
-
Windows10以降 Visual Studio 2022
前提知識
-
C++の基本構文をある程度知っていること。
DLL側のセットアップ方法
Visual Studio 2022を開いて、新しいプロジェクトの作成をクリックします。

ダイナミックリンクライブラリ(DLL)のテンプレートを選択して、右下の次へをクリックしてください。

プロジェクト名と作成するディレクトリを選択して、右下の作成をクリックしてください。

画面右のソリューションエクスプローラーの自身のプロジェクト(本記事ではDllTest)を右クリックし、プロパティをクリックしてプロパティウィンドウを開いてください。

プロパティウィンドウの左側から構成プロパティ->C/C++->プリコンパイル済みヘッダーをクリックし、ウィンドウ右のプリコンパイル済みヘッダーでプリコンパイル済みヘッダーを使用しないを選択してウィンドウ下の適用をクリックしてください。
自身のプロジェクトでプリコンパイル済みヘッダーを使用する場合は、この作業は行わなくて構いません。

これで、ひな型となるプロジェクトのセットアップが完了しました。

DLL側の作成手順
まずは、DLL側のサンプルコードを記述します。
ハローワールドを出力する関数をDLLで作成するサンプルコード
#pragma once
//--------------------------------------------------------------
// @file MyPrint.h
// @brief PrintHelloWorldを出力するDLLのヘッダーファイル
//--------------------------------------------------------------
extern "C" {
//--------------------------------------------------------------
// コンソールにハローワールドを出力する関数
//--------------------------------------------------------------
__declspec(dllexport) void PrintHelloWorld();
}
//--------------------------------------------------------------
// @file MyPrint.cpp
// @brief PrintHelloWorldを出力するDLLの実装ファイル
//--------------------------------------------------------------
#include <iostream>
#include "MyPrint.h"
//--------------------------------------------------------------
// @brief コンソールにハローワールドを出力する関数
//--------------------------------------------------------------
void PrintHelloWorld() {
std::cout << "Hello, World!" << std::endl;
}
__declspec()は、関数や変数の宣言に属性を追加したい場合につけます。
dllexportは、DLLから関数や変数を外部に公開する際に付属させる属性となります。
//--------------------------------------------------------------
// コンソールにハローワールドを出力する関数
//--------------------------------------------------------------
__declspec(dllexport) void PrintHelloWorld();
C++は名前修飾/name manglingという仕組みで関数名を内部的に変換するのですが、DLLを呼び出す際に、変換された後の名前を使用しなくてはなくなります。
extern "C" {}で囲んでやることでC言語形式での公開、つまり内部的な名前の変換を行わないようにし、呼び出し側でも同じ関数名で呼び出すことができます。
extern "C" {
//--------------------------------------------------------------
// コンソールにハローワールドを出力する関数
//--------------------------------------------------------------
__declspec(dllexport) void PrintHelloWorld();
}
これでDLL側のコードが完成したので、ビルドを行います。
画面上部のGUIからビルド構成をReleaseに変更してください。

画面上部のビルドからソリューションのビルドをクリックします。

ビルドに成功したら、プロジェクトのx64->Releaseを開き、.dllと.libファイルがあることを確認してください。

呼び出し側のセットアップ
Visual Studio 2022を開いて、新しいプロジェクトの作成をクリックします。

空のプロジェクトを選択して右下の次へをクリックします。

プロジェクト名を決めて、右下の作成をクリックします。

作成したソリューションのディレクトリにlibという名前のディレクトリを追加します。(後に正しくパスを指定すれば名前はなんでも構いません。)

ここに.libファイルを配置してください。
.dllをここに配置すると、VisualStudio 2022のデバッグ実行で挙動を確認することもできます。

includeという名前のディレクトリを作成します。(こちらも正しくパス指定できればどんな名前でも構いません。)

includeに先ほど作成したdllのヘッダーファイルを配置します。
使用側ではcppファイルは不必要です。

上部GUIのプロジェクトからプロパティをクリックしてプロパティウィンドウを開いてください。

ウィンドウ左側の構成プロパティ->C/C++を選択し、ウィンドウ右の追加のインクルードディレクトリからヘッダーファイルのある場所のパスを追加してください。
本記事の場合はincludeを選択します。

次に、プロパティウィンドウの左側から構成プロパティ->リンカーを選択し、ウィンドウ右から追加のライブラリディレクトリに.libを配置したパスを追加します。
本記事の場合はlibを選択します。

最後に、プロパティウィンドウの左側から構成プロパティ->リンカー->入力を選択し、右側の追加の依存ファイルに.libファイルの名前を追加します。
本記事はDllTest.libと入力します。

プロパティウィンドウの右下の適用をクリックして変更を適用してください。

これでセットアップが完了となります。
呼び出し側のコード例
作成したDLLを呼び出すコード例
#include <iostream>
#include "MyPrint.h" // DLL側で公開したヘッダーをインクルード
//-------------------------------------------------------------
// DLLからインポートする関数を宣言
//-------------------------------------------------------------
extern "C" {
__declspec(dllimport) void PrintHelloWorld();
}
int main() {
// DLLの関数を呼び出す
PrintHelloWorld();
system("pause");
return 0;
}
先ほど、作成側ではdllexportの属性をつけましたが、呼び出し側ではdllimportの属性をつけ、使用したい関数を宣言します。
extern "C" {}で囲わなければ修飾された名前で関数を探しに行ってしまうため、呼び出し側でも囲う必要があります。
ビルドと実行
上部GUIから構成をReleaseに変更します。

上部GUIのビルドからソリューションのビルドをクリックし、exeファイルを作成します。

エクスプローラーのx64->Releaseを開き、ディレクトリにコード中に使用した内容が記述されている.dllファイルを配置してください。
本記事ではDllTest.dllとなります。

exeファイルをクリックして実行を行ってください。

Hello, World!
続行するには何かキーを押してください . . .
.dllに記述した関数を呼び出すことに成功しました。
総括
-
DLLの仕組みを利用することで、共通の機能をひとつのファイルにまとめ、複数のプロジェクトで同じコードを呼び出すことが可能となる。 -
extern "C" {}で囲うことで、C++特有の名前の修飾を回避できる。 -
DLLの場合は、呼び出し側でcppファイルは不要となる。