VC PlusPlus:LIB/DLLの生成とLIB呼び出し、DLL呼び出しについて
概要
DLLやLIBを自作する基礎についての記事です。LIBファイルはDLLを作成すると同じフォルダに吐き出されます。なのでDLLを作成する記事になります。それから生成したLIBファイルとDLLを使う基礎についても記述します。
DLLを作成する
そもそも、この記事はVisual Studio C++記事の子記事ですので、Visual Studioを使ったDLLの作成方法を示すものです。
1.Visual Studio 2022 CommunityでC++のプロジェクトを作成するためのツールを起動します。スタートアップダイアログで、プロジェクトの新規作成を選択します。
2.テンプレート一覧から、ダイナミックリンクライブラリを選択します。
3.ソリューション名を入力します。ここではCppDLLとします。プロジェクト名も同一とします。ソリューションファイルとプロジェクトファイルは同じディレクトリの配置します。作成するディレクトリは規定値(C:\User\(ユーザID)\source\repos\)を使います。
4.ソリューションエクスプローラーの[Header File]を右クリックして表示されるコンテクストメニューから[追加]-[新規の項目]を選択します。
5.ヘッダーファイルを追加するので、ファイル名欄に「CppDLL.h」と指定して[OK]ボタンを押します。
6.以下のようにプログラムを記述します。
int ifDllfunc(void) という関数を外部から使えるようにするためのヘッダファイルです。
#pragma once
#ifndef __CPPDLL_H
#define __CPPDLL_H
#ifdef CPPDLL_EXPORTS
#define CPPDLL_API __declspec(dllexport)
#else
#define CPPDLL_API __declspec(dllimport)
#endif
#ifdef __cplusplus
extern "C" {
#endif
CPPDLL_API int ifDllfunc(void);
#ifdef __cplusplus
}
#endif
#endif
コードの説明
CPPDLL_EXPORTS は、CppDLLプロジェクトを自動生成した時点で定義されているマクロです。DLLの生成側のプロジェクトであることを意味付けるためのマクロです。
CPPDLL_EXPORTS が定義されている、本プロジェクトから、このヘッダファイルが参照されている場合には、DLLを出力するという意味のキーワードをつけた関数を定義する必要がありますので CPPDLL_API というマクロに __declspec(dllexport) を割り当てています。他のアプリからヘッダファイルが呼び出された時は、CPPDLL_EXPORTS が定義されていないので、CPPDLL_API というマクロに __declspec(dllimport) を割り当てています。関数はdllからimportされることを意味します。
extern "C" { … } で関数を囲うことで、C言語の関数定義方法を使うことを宣言したことになります。名前修飾を行わないようにするために必須です。拡張子が *.cpp のファイルをC++としてコンパイルするときにはマクロ定義 __cplusplus がされているので、その場合だけ extern の定義をする形式にしています。CppのプロジェクトなのでライブラリがCでコンパイルされることを想定しなくても良さそうに思えますが、優しさですね。
つまり、このような形式を使ってマクロ定義を切り替える仕組みはDLL作成において必須の記述になっていて無駄な記述ではありません。呼び出しにも対応する上ではプログラムをこれ以上に短くすることはできないです。最低限必要なことが詰め込まれています。
7.自動で生成されたdllmain.cppファイルのDllMain関数の外側にint型の数値を返す関数を記述します。以下のようなコードです。
#include "pch.h"
//追記ここから
#include "CppDLL.h"
CPPDLL_API int ifDllfunc(void){
return 99;
}
//追記ここまで
BOOL APIENTRY DllMain(…
8.Visual Studioのメニュー[ビルド]-[ビルド]を選択。
- これで、ソリューション・プロジェクトファイルを作成したディレクトリから見て、.\x64\Debug\ フォルダに CppDLL.dll と CppDll.libが作成されます。この libファイルは CppDLL.h を使う場合には dll が必要となる状態です。CppDll.lib 単独で使うには __declspec(dllimport) キーワードがついていないヘッダファイルを用意する必要があります。そういったヘッダファイルになるようにもう一工夫すると、ライブラリで使うヘッダファイルも作れると思います。例えば、以下のように改造します。
#pragma once
#ifndef __CPPDLL_H
#define __CPPDLL_H
#ifdef CPPDLL_EXPORTS
#define CPPDLL_API __declspec(dllexport)
#else
#ifdef CPPLIB_EXPORTS
#define CPPDLL_API
#else
#define CPPDLL_API __declspec(dllimport)
#endif
#endif
#ifdef __cplusplus
extern "C" {
#endif
CPPDLL_API int ifDllfunc(void);
#ifdef __cplusplus
}
#endif
#endif
コードの説明
8行目~12行目を追加しました。if文をネストするような形式で、CPPLIB_EXPORTS が定義されている場合の処理を追加しています。CPPLIB_EXPORTS と定義されていた時には CPPDLL_API を置き換えるマクロ定数を設定しないようになっています。呼び出し側でマクロを定義する必要はあります。普通はDLLで提供するかLIBで提供するかどっちかだと思うので、lib用にも対応するというのはあまりしないかもしれません。