チュートリアル: 独自のダイナミック リンク ライブラリを作成して使用する (C++)
このチュートリアルでは、Visual Studio IDE を使用して Microsoft C++ (MSVC) で記述された独自のダイナミック リンク ライブラリ (DLL) を作成する方法について順を追って説明します。 その後、その DLL を別の C++ アプリから使用する方法を示します。 DLL (UNIX ベースのオペレーティング システムでは共有ライブラリとも呼ばれます) は、特に役立つ Windows コンポーネントの種類の 1 つです。 それらを使用して、コードやリソースを共有したり、アプリのサイズを縮小したりできます。 DLL を使用すると、アプリのサービス提供や拡張も簡単になります。
このチュートリアルでは、いくつかの数値演算関数を実装する DLL を作成します。 その後、DLL の関数を使用するコンソール アプリを作成します。 また、Windows DLL で使用されるいくつかのプログラミング手法や規則についても紹介します。
このチュートリアルでは、次の作業について説明します。
Visual Studio で DLL プロジェクトを作成します。
エクスポートされた関数と変数を DLL に追加します。
Visual Studio でコンソール アプリ プロジェクトを作成します。
コンソール アプリで DLL からインポートした関数と変数を使います。
完成したアプリを実行します。
静的にリンクされたライブラリと同様に、DLL では変数、関数、およびリソースが名前で "エクスポート" されます。 クライアント アプリでは、それらの変数、関数、およびリソースを使用するために、その名前が "インポート" されます。 静的にリンクされるライブラリとは異なり、読み込み時または実行時に Windows によってアプリのインポートが DLL のエクスポートに結合されます。リンク時に結合するのではありません。 これらの結合を行うには、標準 C++ コンパイル モデルには含まれていない補足情報が Windows に必要です。 MSVC コンパイラには、この補足情報を提供するための Microsoft 固有の C++ 拡張機能がいくつか実装されています。 これらの拡張機能について順次説明していきます。
このチュートリアルでは 2 つの Visual Studio ソリューションを作成します。DLL を構築するものと、クライアント アプリを構築するものです。 DLL では、C 呼び出し規則が使用されます。 これは、プラットフォーム、呼び出し規則、リンク規則が一致すれば、他のプログラミング言語で記述されたアプリから呼び出すことができます。 クライアント アプリでは、読み込み時に Windows によってアプリが DLL にリンクされる、"暗黙的リンク" を使います。 このリンクを使うことで、静的にリンクされたライブラリの関数と同じように、DLL で指定した関数をアプリから呼び出すことができます。
このチュートリアルでは一部の一般的な状況を扱っていません。 このコードには、他のプログラミング言語による C++ DLL の使用については示されていません。 リソースのみの DLL を作成する方法や、明示的リンクを使用して読み込み時ではなく実行時に DLL を読み込む方法については示されていません。 ご安心ください。MSVC と Visual Studio を使用してこれらすべての作業を行えます。
DLL のコードは C++ で記述されていますが、エクスポートされた関数には C スタイルのインターフェイスを使用しました。 これには主に 2 つの理由があります。まず、他の多くの言語では、C スタイルの関数のインポートがサポートされています。 クライアント アプリを C++ で記述する必要はありません。 次に、エクスポートされたクラスとメンバー関数に関連する、よくある落とし穴が回避されます。 クラス宣言内で参照されるすべてのものに、同様にエクスポートされるインスタンス化が必要なので、クラスのエクスポート時に、診断が困難な間違いが起きやすくなります。 この制限は DLL に適用されますが、静的ライブラリには適用されません。 クラスが単純な従来のデータ スタイルの場合は、この問題は発生しないはずです。
DLL に関する詳細情報へのリンクについては、「Visual Studio での C/C++ Dll の作成」をご覧ください。 暗黙的リンクと明示的リンクについて詳しくは、リンク方法の使い分けに関するページをご覧ください。 C 言語のリンケージ規則が使われるプログラミング言語と共に使う C++ DLL を作成する方法について詳しくは、「C 言語の実行形式で使う C++ 関数のエクスポート」をご覧ください。 .NET 言語で使う DLL を作成する方法については、「DLL 関数の Visual Basic アプリケーションからの呼び出し方」をご覧ください。
前提条件
- Microsoft Windows 7 またはそれ以降のバージョンを稼働しているコンピューター。 最高の開発エクスペリエンスには、Windows の最新バージョンをお勧めします。
Visual Studio。 Visual Studio をダウンロードしてインストールする方法について詳しくは、「Visual Studio のインストール」をご覧ください。 インストーラーを実行するときに、[C++ によるデスクトップ開発] ワークロードがオンになっていることを確認してください。 Visual Studio をインストールしたときにこのワークロードをインストールしていなくても問題ありません。 インストーラーをもう一度実行して、すぐにインストールできます。
- Visual Studio。 Visual Studio 2015 をダウンロードしてインストールする方法について詳しくは、「Visual Studio 2015 のインストール」をご覧ください。 C++ コンパイラとツールは既定ではインストールされないため、カスタム インストールを使用してインストールしてください。
Visual Studio IDE の使用に関する基本事項の理解。 以前に Windows デスクトップ アプリを使ったことがあれば、おそらく問題ありません。 概要については、Visual Studio IDE の機能ツアーに関するページをご覧ください。
内容を理解するための、C++ 言語の基本に関する十分な理解。 あまり複雑な作業は行わないので、ご安心ください。
Note
このチュートリアルは、Visual Studio 2017 バージョン 15.9 以降を使用していることを前提としています。 以前のバージョンの Visual Studio 2017 では、コード テンプレートに欠陥があるか、別のユーザー インターフェイス ダイアログが使用されていました。 問題を回避するには、Visual Studio インストーラーを使用して Visual Studio 2017 をバージョン 15.9 以降に更新してください。
DLL プロジェクトを作成する
この一連のタスクでは、DLL のプロジェクトを作成して、コードを追加し、ビルドします。 最初に、Visual Studio IDE を起動して、必要に応じてサインインします。 使用している Visual Studio のバージョンによって、手順が若干異なります。 このページの左上のコントロールで適切なバージョンを選択していることを確認してください。
Visual Studio 2019 で DLL プロジェクトを作成するには
メニューバーで、 [ファイル]>[新規作成]>[プロジェクト] の順に選択して、 [新しいプロジェクトの作成] ダイアログ ボックスを開きます。
ダイアログの上部で、[言語] を [C++] に、[プラットフォーム] を [Windows] に、[プロジェクト タイプ] を [ライブラリ] に設定します。
フィルター処理されたプロジェクト タイプの一覧から、[ダイナミック リンク ライブラリ (DLL)] を選択して、[次へ] を選択します。
[新しいプロジェクトの構成] ページで、[プロジェクト名] ボックスに「MathLibrary」と入力して、プロジェクトの名前を指定します。 [場所] および [ソリューション名] の値は既定のままにします。 [ソリューション] を [新しいソリューションを作成する] に設定します。 オンになっている場合は、[ソリューションとプロジェクトを同じディレクトリに配置する] をオフにします。
[作成] ボタンをクリックしてプロジェクトを作成します。
ソリューションが作成されたら、Visual Studio の [ソリューション エクスプローラー] ウィンドウで、生成されたプロジェクトとソース ファイルを確認できます。
Visual Studio 2017 で DLL プロジェクトを作成するには
メニューバーで、[ファイル]>[新規作成]>[プロジェクト] の順に選択して、[新しいプロジェクト] ダイアログ ボックスを開きます。
[新しいプロジェクト] ダイアログ ボックスの左側のペインで、[インストール済み]>[Visual C++]>[Windows デスクトップ] を選択します。 中央のペインで、[ダイナミック リンク ライブラリ (DLL)] を選択します。 [名前] ボックスに「MathLibrary」と入力してプロジェクトの名前を指定します。 [場所] および [ソリューション名] の値は既定のままにします。 [ソリューション] を [新しいソリューションを作成する] に設定します。 オフになっている場合は、[ソリューションのディレクトリを作成] をオンにします。
[OK] ボタンを選択すると、プロジェクトが作成されます。
ソリューションが作成されたら、Visual Studio の [ソリューション エクスプローラー] ウィンドウで、生成されたプロジェクトとソース ファイルを確認できます。
Visual Studio 2015 以前のバージョンで DLL プロジェクトを作成するには
メニュー バーで、 [ファイル]>[新規作成]>[プロジェクト] を選択します。
[新しいプロジェクト] ダイアログ ボックスの左側のウィンドウで、[インストール済み]>[テンプレート] を展開して [Visual C++] を選択してから、中央のウィンドウで [Win32 コンソール アプリケーション] を選択します。 [名前] エディット ボックスに「MathLibrary」と入力してプロジェクトの名前を指定します。 [場所] および [ソリューション名] の値は既定のままにします。 [ソリューション] を [新しいソリューションを作成する] に設定します。 オフになっている場合は、[ソリューションのディレクトリを作成] をオンにします。
[OK] ボタンを選択して [新しいプロジェクト] ダイアログを閉じ、 [Win32 アプリケーション ウィザード] を起動します。
[次へ] ボタンをクリックします。 [アプリケーションの設定] ページの [アプリケーションの種類] の下で、[DLL] を選択します。
[完了] をクリックすると、プロジェクトが作成されます。
ウィザードでソリューションが完了したら、Visual Studio の [ソリューション エクスプローラー] ウィンドウで、生成されたプロジェクトとソース ファイルを確認できます。
現時点では、この DLL にはほとんど意味がありません。 次は、DLL でエクスポートした関数を宣言するためのヘッダー ファイルを作成した後、DLL に関数の定義を追加してこれをより役立つものにします。
DLL にヘッダー ファイルを追加するには
関数のヘッダー ファイルを作成するには、メニュー バーで [プロジェクト]>[新しい項目の追加] の順に選択します。
[新しい項目の追加] ダイアログ ボックスの左側のウィンドウで、[Visual C++] を選択します。 中央のウィンドウで、 [ヘッダー ファイル (.h)]をクリックします。 ヘッダー ファイルの名前として「MathLibrary.h」を指定します。
[追加] ボタンを選択して空白のヘッダー ファイルを生成します。これは新しいエディター ウィンドウに表示されます。
ヘッダー ファイルの内容を次のコードに置き換えます。
// MathLibrary.h - Contains declarations of math functions #pragma once #ifdef MATHLIBRARY_EXPORTS #define MATHLIBRARY_API __declspec(dllexport) #else #define MATHLIBRARY_API __declspec(dllimport) #endif // The Fibonacci recurrence relation describes a sequence F // where F(n) is { n = 0, a // { n = 1, b // { n > 1, F(n-2) + F(n-1) // for some initial integral values a and b. // If the sequence is initialized F(0) = 1, F(1) = 1, // then this relation produces the well-known Fibonacci // sequence: 1, 1, 2, 3, 5, 8, 13, 21, 34, ... // Initialize a Fibonacci relation sequence // such that F(0) = a, F(1) = b. // This function must be called before any other function. extern "C" MATHLIBRARY_API void fibonacci_init( const unsigned long long a, const unsigned long long b); // Produce the next value in the sequence. // Returns true on success and updates current value and index; // false on overflow, leaves current value and index unchanged. extern "C" MATHLIBRARY_API bool fibonacci_next(); // Get the current value in the sequence. extern "C" MATHLIBRARY_API unsigned long long fibonacci_current(); // Get the position of the current value in the sequence. extern "C" MATHLIBRARY_API unsigned fibonacci_index();
このヘッダー ファイルでは、2 つの初期値を指定して、一般化されたフィボナッチ数列を生成するための関数をいくつか宣言しています。 fibonacci_init(1, 1)
を呼び出すと、有名なフィボナッチ数の数列が生成されます。
ファイルの上部にあるプリプロセッサのステートメントに注目します。 DLL プロジェクトの新しいプロジェクト テンプレートによって、<PROJECTNAME>_EXPORTS
が定義済みプリプロセッサ マクロに追加されます。 この例では、Visual Studio によって、MathLibrary DLL プロジェクトのビルド時に MATHLIBRARY_EXPORTS
が定義されます。
MATHLIBRARY_EXPORTS
マクロが定義されている場合、MATHLIBRARY_API
マクロでは関数宣言に __declspec(dllexport)
修飾子を設定します。 この修飾子により、他のアプリケーションで使用できるように、DLL から関数または変数をエクスポートするよう、コンパイラとリンカーに指示が出されます。 MATHLIBRARY_EXPORTS
が未定義の場合 (たとえば、クライアント アプリケーションによってヘッダー ファイルが含まれる場合)、MATHLIBRARY_API
によって宣言に __declspec(dllimport)
修飾子が適用されます。 この修飾子によって、アプリケーションへの関数または変数のインポートが最適化されます。 詳細については、「dllexport、dllimport」をご覧ください。
DLL に実装を追加するには
ソリューション エクスプローラーで、Source Files ノードを右クリックし、[追加]>[新しい項目] の順に選択します。 前の手順で新しいヘッダー ファイルを追加したのと同じ方法で、MathLibrary.cpp という名前の新しい .cpp ファイルを作成します。
エディター ウィンドウで、既に開いている場合は MathLibrary.cpp のタブを選択します。 そうでない場合は、ソリューション エクスプローラーで、MathLibrary プロジェクトの Source Files フォルダーにある MathLibrary.cpp をダブルクリックして開きます。
エディターで、MathLibrary.cpp ファイルの内容を次のコードに置き換えます。
// MathLibrary.cpp : Defines the exported functions for the DLL. #include "pch.h" // use stdafx.h in Visual Studio 2017 and earlier #include <utility> #include <limits.h> #include "MathLibrary.h" // DLL internal state variables: static unsigned long long previous_; // Previous value, if any static unsigned long long current_; // Current sequence value static unsigned index_; // Current seq. position // Initialize a Fibonacci relation sequence // such that F(0) = a, F(1) = b. // This function must be called before any other function. void fibonacci_init( const unsigned long long a, const unsigned long long b) { index_ = 0; current_ = a; previous_ = b; // see special case when initialized } // Produce the next value in the sequence. // Returns true on success, false on overflow. bool fibonacci_next() { // check to see if we'd overflow result or position if ((ULLONG_MAX - previous_ < current_) || (UINT_MAX == index_)) { return false; } // Special case when index == 0, just return b value if (index_ > 0) { // otherwise, calculate next sequence value previous_ += current_; } std::swap(current_, previous_); ++index_; return true; } // Get the current value in the sequence. unsigned long long fibonacci_current() { return current_; } // Get the current index position in the sequence. unsigned fibonacci_index() { return index_; }
エディター ウィンドウで、既に開いている場合は MathLibrary.cpp のタブを選択します。 そうでない場合は、ソリューション エクスプローラーで、MathLibrary プロジェクトの Source Files フォルダーにある MathLibrary.cpp をダブルクリックして開きます。
エディターで、MathLibrary.cpp ファイルの内容を次のコードに置き換えます。
// MathLibrary.cpp : Defines the exported functions for the DLL. #include "stdafx.h" // use pch.h in Visual Studio 2019 and later #include <utility> #include <limits.h> #include "MathLibrary.h" // DLL internal state variables: static unsigned long long previous_; // Previous value, if any static unsigned long long current_; // Current sequence value static unsigned index_; // Current seq. position // Initialize a Fibonacci relation sequence // such that F(0) = a, F(1) = b. // This function must be called before any other function. void fibonacci_init( const unsigned long long a, const unsigned long long b) { index_ = 0; current_ = a; previous_ = b; // see special case when initialized } // Produce the next value in the sequence. // Returns true on success, false on overflow. bool fibonacci_next() { // check to see if we'd overflow result or position if ((ULLONG_MAX - previous_ < current_) || (UINT_MAX == index_)) { return false; } // Special case when index == 0, just return b value if (index_ > 0) { // otherwise, calculate next sequence value previous_ += current_; } std::swap(current_, previous_); ++index_; return true; } // Get the current value in the sequence. unsigned long long fibonacci_current() { return current_; } // Get the current index position in the sequence. unsigned fibonacci_index() { return index_; }
今のところすべてが機能していることを確認するために、ダイナミック リンク ライブラリをコンパイルします。 コンパイルするには、メニュー バーで [ビルド]>[ソリューションのビルド] の順に選択します。 DLL および関連するコンパイラの出力は、ソリューション フォルダーの直下にある Debug という名前のフォルダーに配置されます。 リリース ビルドを作成すると、出力は Release という名前のフォルダーに配置されます。 出力は次のようになります。
1>------ Build started: Project: MathLibrary, Configuration: Debug Win32 ------
1>pch.cpp
1>dllmain.cpp
1>MathLibrary.cpp
1>Generating Code...
1> Creating library C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.lib and object C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.exp
1>MathLibrary.vcxproj -> C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.dll
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
1>------ Build started: Project: MathLibrary, Configuration: Debug Win32 ------
1>stdafx.cpp
1>dllmain.cpp
1>MathLibrary.cpp
1>Generating Code...
1> Creating library C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.lib and object C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.exp
1>MathLibrary.vcxproj -> C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.dll
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
1>------ Build started: Project: MathLibrary, Configuration: Debug Win32 ------
1>MathLibrary.cpp
1>dllmain.cpp
1>Generating Code...
1> Creating library C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.lib and object C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.exp
1>MathLibrary.vcxproj -> C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.dll
1>MathLibrary.vcxproj -> C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.pdb (Partial PDB)
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
これで Visual C++ を使用して DLL が作成されました。 次は、DLL によってエクスポートされた関数を使用するクライアント アプリを作成します。
DLL を使用するクライアント アプリを作成する
DLL を作成するときは、クライアント アプリでの使用方法について検討してください。 関数を呼び出したり、DLL によってエクスポートされたデータにアクセスしたりするには、コンパイル時にクライアントのソース コードで宣言を使用できるようにする必要があります。 リンク時、リンカーには関数呼び出しまたはデータ アクセスを解決するための情報を必要とします。 この情報は DLL によって "インポート ライブラリ" に提供されます。これは、実際のコードではなく、関数とデータを検索する方法に関する情報が含まれるファイルです。 そして実行時に、オペレーティング システムによって見つけられる場所で、クライアントが DLL を利用できる必要があります。
クライアント アプリ プロジェクトでは、それが独自のものであっても、サードパーティ製であっても、DLL を使用するためにいくつかの情報を必要とします。 ここでは、DLL のエクスポートを宣言するヘッダー、リンカー用のインポート ライブラリ、DLL 自体を見つける必要があります。 1 つの解決策は、これらすべてのファイルをクライアント プロジェクトにコピーすることです。 クライアントの開発中に変更される可能性が低いサード パーティ製の DLL については、この方法がそれらを使うための最善の方法である場合があります。 ただし、自分で DLL もビルドする場合は、重複を避けることをお勧めします。 開発中の DLL ファイルのローカル コピーを作成する場合、誤って 1 つのコピーのヘッダー ファイルだけを変更したり、古いライブラリを使用したりする可能性があります。
コードが非同期になるのを回避するために、クライアント プロジェクトのインクルード パスを設定して、DLL プロジェクトから DLL のヘッダー ファイルを直接インクルードすることをお勧めします。 また、クライアント プロジェクトのライブラリ パスを設定して、DLL プロジェクトから DLL インポート ライブラリをインクルードするようにします。 そして最後に、ビルドした DLL を DLL プロジェクトからクライアント ビルド出力ディレクトリにコピーします。 この手順により、自分でビルドする同じ DLL のコードをクライアント アプリで使えます。
Visual Studio でクライアント アプリを作成するには
メニューバーで、[ファイル]>[新規作成]>[プロジェクト] の順に選択して、[新しいプロジェクトの作成] ダイアログ ボックスを開きます。
ダイアログの上部で、[言語] を [C++] に、[プラットフォーム] を [Windows] に、[プロジェクト タイプ] を [コンソール] に設定します。
フィルター処理されたプロジェクト タイプの一覧から、 [コンソール アプリ] を選択して、 [次へ] を選択します。
[新しいプロジェクトの構成] ページで、[プロジェクト名] ボックスに「MathClient」と入力して、プロジェクトの名前を指定します。 [場所] および [ソリューション名] の値は既定のままにします。 [ソリューション] を [新しいソリューションを作成する] に設定します。 オンになっている場合は、[ソリューションとプロジェクトを同じディレクトリに配置する] をオフにします。
[作成] ボタンを選択してクライアント プロジェクトを作成します。
最小限のコンソール アプリケーション プロジェクトが自動的に作成されます。 メイン ソース ファイルの名前は、以前に入力したプロジェクト名と同じです。 この例では、MathClient.cpp という名前が付いています。 これはビルドできますが、まだ DLL が使われていません。
Visual Studio 2017 でクライアント アプリを作成するには
作成した DLL を使用する C++ アプリを作成するには、メニュー バーで [ファイル]>[新規作成]>[プロジェクト] の順に選択します。
[新しいプロジェクト] ダイアログの左側のウィンドウで、[インストール済み]>[Visual C++] の下の [Windows デスクトップ] を選択します。 中央のペインで [Windows コンソール アプリケーション] を選択します。 [名前] エディット ボックスに、プロジェクトの名前 (MathClient) を指定します。 [場所] および [ソリューション名] の値は既定のままにします。 [ソリューション] を [新しいソリューションを作成する] に設定します。 オフになっている場合は、[ソリューションのディレクトリを作成] をオンにします。
[OK] を選択してクライアント アプリ プロジェクトを作成します。
最小限のコンソール アプリケーション プロジェクトが自動的に作成されます。 メイン ソース ファイルの名前は、以前に入力したプロジェクト名と同じです。 この例では、MathClient.cpp という名前が付いています。 これはビルドできますが、まだ DLL が使われていません。
Visual Studio 2015 でクライアント アプリを作成するには
作成した DLL を使用する C++ アプリを作成するには、メニュー バーで [ファイル]>[新規作成]>[プロジェクト] の順に選択します。
[新しいプロジェクト] ダイアログの左側のウィンドウで、[インストール済み]>[テンプレート]>[Visual C++] の下の [Win32] を選択します。 中央のウィンドウで [Win32 コンソール アプリケーション]をクリックします。 [名前] エディット ボックスに、プロジェクトの名前 (MathClient) を指定します。 [場所] および [ソリューション名] の値は既定のままにします。 [ソリューション] を [新しいソリューションを作成する] に設定します。 オフになっている場合は、[ソリューションのディレクトリを作成] をオンにします。
[OK] ボタンを選択して [新しいプロジェクト] ダイアログを閉じ、 [Win32 アプリケーション ウィザード] を起動します。 [Win32 アプリケーション ウィザード] ダイアログ ボックスの [概要] ページで、 [次へ] をクリックします。
[アプリケーションの設定] ページの [アプリケーションの種類] の下で、[コンソール アプリケーション] がまだ選択されていない場合はこれを選択します。
[完了] をクリックすると、プロジェクトが作成されます。
ウィザードが完了したら、最小限のコンソール アプリケーション プロジェクトが自動的に作成されます。 メイン ソース ファイルの名前は、以前に入力したプロジェクト名と同じです。 この例では、MathClient.cpp という名前が付いています。 これはビルドできますが、まだ DLL が使われていません。
次に、ソース コードで MathLibrary 関数を呼び出すには、プロジェクトに MathLibrary.h ファイルを含める必要があります。 クライアント アプリ プロジェクトにこのヘッダー ファイルをコピーした後、既存のアイテムとしてこれをプロジェクトに追加することができます。 この方法は、サード パーティ製のライブラリに最適である場合があります。 ただし、DLL とクライアントのコードを同時に操作している場合は、ヘッダー ファイルが同期を失う可能性があります。この問題を回避するには、プロジェクトの [追加インクルード ディレクトリ] パスを、元のヘッダーへのパスを含むように設定します。
インクルード パスに DLL のヘッダーを追加するには
[ソリューション エクスプローラー] で [MathClient] ノードを右クリックして、[プロパティ ページ] ダイアログを開きます。
[構成] ドロップダウン ボックスで、[すべての構成] がまだ選択されていない場合はこれを選択します。
左側のペインで、[構成プロパティ]>[C/C++]>[全般] を選択します。
プロパティ ウィンドウで、[追加のインクルード ディレクトリ] エディット ボックスの横にあるドロップダウン コントロールを選択してから、[編集] を選択します。
[追加のインクルード ディレクトリ] ダイアログ ボックスの上部のウィンドウ内をダブルクリックして、編集コントロールを有効にします。 または、フォルダー アイコンをクリックして新しいエントリを作成します。
編集コントロールで、MathLibrary.h ヘッダー ファイルの場所へのパスを指定します。 省略記号 (...) コントロールを選択して、適切なフォルダーを参照できます。
または、クライアント ソース ファイルから DLL ヘッダー ファイルが格納されているフォルダーへの相対パスを入力することもできます。 クライアント プロジェクトを DLL とは別のソリューションに配置する指示に従った場合、相対パスは次のようになります。
..\..\MathLibrary\MathLibrary
DLL とクライアント プロジェクトが同じソリューション内にある場合、相対パスは次のようになります。
..\MathLibrary
DLL プロジェクトとクライアント プロジェクトが別のフォルダーにあるときは、一致するように相対パスを調整します。 または、省略記号コントロールを使用してフォルダーを参照します。
[追加のインクルード ディレクトリ] ダイアログ ボックスにヘッダー ファイルへのパスを入力したら、[OK] ボタンを選択します。 [プロパティ ページ] ダイアログ ボックスで、[OK] ボタンをクリックして変更を保存します。
これで MathLibrary.h ファイルをインクルードして、それで宣言した関数をクライアント アプリケーション内で使えるようになりました。 次のコードを使って、MathClient.cpp の内容を置き換えます。
// MathClient.cpp : Client app for MathLibrary DLL.
// #include "pch.h" Uncomment for Visual Studio 2017 and earlier
#include <iostream>
#include "MathLibrary.h"
int main()
{
// Initialize a Fibonacci relation sequence.
fibonacci_init(1, 1);
// Write out the sequence values until overflow.
do {
std::cout << fibonacci_index() << ": "
<< fibonacci_current() << std::endl;
} while (fibonacci_next());
// Report count of values written before overflow.
std::cout << fibonacci_index() + 1 <<
" Fibonacci sequence values fit in an " <<
"unsigned 64-bit integer." << std::endl;
}
このコードはコンパイルできますが、リンクされません。 クライアント アプリを今すぐビルドすると、エラー一覧に LNK2019 のエラーがいくつか表示されます。 これは、プロジェクトに情報が不足しているためです。プロジェクトが MathLibrary.lib ライブラリに依存していることをまだ指定していません。 また、リンカーに MathLibrary ファイルの検索方法を指示していません。
この問題を解決するには、ライブラリ ファイルをクライアント アプリ プロジェクトに直接コピーします。 このファイルは、リンカーにより自動的に検索され、使用されます。 ただし、ライブラリとクライアント アプリの両方が開発中である場合は、それによって他からは見えない 1 つのコピーに対する変更が生じる場合があります。 この問題を回避するには、[追加の依存ファイル] プロパティを設定して、プロジェクトが MathLibrary.lib に依存していることをビルド システムに指示します。 また、リンク時に、プロジェクトの [追加のライブラリ ディレクトリ] パスを、元のライブラリへのパスを含めるよう設定します。
プロジェクトに DLL インポート ライブラリを追加するには
ソリューション エクスプローラーで MathClient ノードを右クリックし、[プロパティ] を選択して、[プロパティ ページ] ダイアログを開きます。
[構成] ドロップダウン ボックスで、[すべての構成] がまだ選択されていない場合はこれを選択します。 これにより、プロパティのすべての変更がデバッグ ビルドとリリース ビルドの両方に適用されます。
左側のペインで、[構成プロパティ]>[リンカー]>[入力] を選択します。 プロパティ ウィンドウで、[追加の依存ファイル] エディット ボックスの横にあるドロップダウン コントロールを選択してから、[編集] を選択します。
[追加の依存ファイル] ダイアログで、上部の編集コントロールのリストに MathLibrary.lib を追加します。
[OK] を選択して、[プロパティ ページ] ダイアログ ボックスに戻ります。
左側のペインで、[構成プロパティ]>[リンカー]>[全般] を選択します。 プロパティ ウィンドウで、[追加のライブラリ ディレクトリ] エディット ボックスの横にあるドロップダウン コントロールを選択してから、[編集] を選択します。
[追加のライブラリ ディレクトリ] ダイアログ ボックスの上部のウィンドウ内をダブルクリックして、編集コントロールを有効にします。 編集コントロールで、MathLibrary.lib ファイルの場所へのパスを指定します。 既定では、DLL ソリューション フォルダーの直下にある Debug という名前のフォルダーにあります。 リリース ビルドを作成すると、ファイルは Release という名前のフォルダーに配置されます。
$(IntDir)
マクロを使用して、作成するビルドの種類に関係なく、リンカーが DLL を検索できるようにします。 クライアント プロジェクトを DLL プロジェクトとは別のソリューションに配置する指示に従った場合、相対パスは次のようになります。..\..\MathLibrary\$(IntDir)
DLL プロジェクトとクライアント プロジェクトが別の場所にある場合は、一致するように相対パスを調整します。
[追加のライブラリ ディレクトリ] ダイアログ ボックスにライブラリ ファイルへのパスを入力したら、[OK] ボタンを選択して [プロパティ ページ] ダイアログ ボックスに戻ります。 [OK] を選択して、プロパティの変更を保存します。
これでクライアント アプリを正常にコンパイルおよびリンクできるようになりましたが、実行のために必要なものはまだ何も含まれていません。 オペレーティング システムによってアプリが読み込まれると、MathLibrary DLL が検索されます。 特定のシステム ディレクトリ、環境パス、またはアプリのローカル ディレクトリに DLL が見つからない場合、読み込みは失敗します。 オペレーティング システムによっては、次のようなエラー メッセージが表示されます。
この問題を回避する方法の 1 つは、ビルド プロセスの一環として、クライアントの実行可能ファイルが置かれているディレクトリに DLL をコピーすることです。 プロジェクトに [ビルド後のイベント] を追加して、ビルド出力ディレクトリに DLL をコピーするコマンドを追加できます。 ここで指定されたコマンドでは、DLL が存在しないか変更されている場合にのみ DLL がコピーされます。 ここではマクロを使用して、ビルド構成に基づいて、Debug または Release の場所の間でコピーされます。
ビルド後のイベントで DLL をコピーするには
ソリューション エクスプローラーで MathClient ノードを右クリックし、[プロパティ] を選択して、[プロパティ ページ] ダイアログを開きます。
[構成] ドロップダウン ボックスで、[すべての構成] がまだ選択されていない場合はこれを選択します。
左側のペインで、[構成プロパティ]>[ビルド イベント]>[ビルド後のイベント] を選択します。
プロパティ ペインで、[コマンド ライン] フィールドの編集コントロールを選択します。 クライアント プロジェクトを DLL プロジェクトとは別のソリューションに配置する指示に従った場合は、このコマンドを入力します。
xcopy /y /d "..\..\MathLibrary\$(IntDir)MathLibrary.dll" "$(OutDir)"
DLL プロジェクトとクライアント プロジェクトが別のディレクトリある場合は、一致するように DLL への相対パスを変更します。
[OK] ボタンを選択して、プロジェクト プロパティに変更を保存します。
これで、クライアント アプリのビルドと実行に必要なものがすべて揃いました。 メニュー バーで [ビルド]>[ソリューションのビルド] の順に選択して、アプリケーションをビルドします。 Visual Studio の [出力] ウィンドウには、Visual Studio のバージョンに応じて、次の例のようなものが必要です。
1>------ Build started: Project: MathClient, Configuration: Debug Win32 ------
1>MathClient.cpp
1>MathClient.vcxproj -> C:\Users\username\Source\Repos\MathClient\Debug\MathClient.exe
1>1 File(s) copied
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
これで、DLL の関数を呼び出すアプリケーションの作成が完了しました。 アプリケーションを実行してその動作を確認してみましょう。 メニュー バーで、[デバッグ]>[デバッグなしで開始] の順に選択します。 プログラムを実行するためのコマンド ウィンドウが Visual Studio により開かれます。 出力の最後の部分は次のようになります。
任意のキーを押して、コマンド ウィンドウを閉じます。
DLL とクライアント アプリケーションを作成したので、実験を行えます。 クライアント アプリのコードにブレークポイントを設定して、デバッガーでアプリを実行してみます。 ライブラリの呼び出しにステップ インするときの動作を確認します。 ライブラリに他の関数を追加するか、DLL を使用する別のクライアント アプリを作成します。
アプリを配置するときに、使われる DLL も配置する必要があります。 サード パーティからビルドまたはインクルードした DLL を使用できるようにするための最も簡単な方法は、それらをアプリと同じディレクトリに置くことです。 "アプリのローカルの配置" と呼ばれます。 配置の詳細については、「 Deployment in Visual C++」を参照してください。