パソコンでプログラミングしよう ウィンドウズC++プログラミング環境の構築
1.6.3.6(15)
ダイナミックリンクライブラリ

ダイナミックリンクライブラリ(DLL)はソフトウェアバイナリ形態の一種で動的リンクを使ったライブラリのこと。

その他の外部情報

本サイトでの解釈

ウィンドウズのダイナミックリンクライブラリは実行時に動的リンクされるライブラリであり、実行ファイル作成時に静的リンクされるスタティックリンクライブラリと区別される。以下にDLLのインターフェースを示す。

  • エクスポート関数
  • コンポーネントオブジェクトモデル
  • .NETフレームワーク

以降は主にエクスポート関数を対象として説明する。

ダイナミックリンクライブラリとスタティックリンクライブラリ

ランタイムライブラリを含む多くのライブラリがDLLとスタティックリンクライブラリを用意し、実行ファイルのリンク時にどちらかを選択する。C++でこのDLLを使用するにはインポートライブラリと呼ばれる仲介のスタティックリンクライブラリをリンクする。このように生成された実行ファイルはロード時にDLLをロードする(ロード時動的リンク)。DLL利用には実行時動的リンクという方法もあるが、後述のようにソースコードレベルで異なる。

本サイトがコンパイラとして使用するmingw-w64(正確にはmingw-w64が子プロセスとして起動するGNUリンカ)はデフォルトでランタイムのDLLインポートライブラリをリンクするが、オプション-staticを用いればスタティックリンクライブラリをリンクする。以下は標準C++ライブラリを供給するランタイムライブラリを例としたMSYS2のmingw64サブシステムにおける説明で、mingw-w64バージョン8.2.1の場合を示してパス名一部にバージョン表記を含む。

ライブラリ ファイル名 MSYS2パス
ダイナミックリンクライブラリ libstdc++-6.dll /mingw64/bin/libstdc++-6.dll
DLLインポートライブラリ libstdc++.dll.a /mingw64/lib/gcc/x86_64-w64-mingw32/8.2.1/libstdc++.dll.a
スタティックリンクライブラリ libstdc++.a /mingw64/lib/gcc/x86_64-w64-mingw32/8.2.1/libstdc++.a

以下はMSYS2のpacmanで追加したライブラリ例として、wxWidgetsバージョン3.0.4のwxBaseライブラリを示す。ランタイムと異なりデフォルトでリンクされないため、リンク時にDLLインポートライブラリあるいはスタティックリンクライブラリを-lオプションで明示する。MSYS2はリンクされるファイルを標準ライブラリディレクトリに置くので、-Lオプションでのライブラリディレクトリの追加は不要となる。

ライブラリ ファイル名 MSYS2パス
ダイナミックリンクライブラリ wxbase30u_gcc_custom.dll /mingw64/bin/wxbase30u_gcc_custom.dll
DLLインポートライブラリ libwx_baseu-3.0.dll.a /mingw64/lib/libwx_baseu-3.0.dll.a
スタティックリンクライブラリ libwx_baseu-3.0.a /mingw64/lib/libwx_baseu-3.0.a

DLLをロード時動的リンクする実行ファイルは対応するDLLがその探索パスに存在する必要がある。POSIXサブシステム環境ではコマンドサーチパス(環境変数PATH)にディレクトリ(上記例では/mingw64/bin)設定されているが、ウィンドウズ環境ではPATHに加えるか実行ファイルと同一ディレクトリにコピーを置く必要がある。

システムDLL

ウィンドウズのシステムコール(ウィンドウズAPI)はオペレーティングシステム中核(カーネル)を直接コールするユニックスライクと異なり、DLLエクスポート関数の形で与えられる。APIを供給するDLLをシステムDLLと呼ぶことがある。多数あるシステムDLLのうち主な三つを例示する。

DLL 機能 API関数の例
kernel.dll メモリ、入出力、プロセス・スレッド、同期 WriteFile, GetProcessHeap, LoadLibrary
gdi32.dll グラフィックデバイスインターフェース CreateFont, BitBlt, ChagneDisplaySettings
user32.dll ユーザーインターフェース MessageBox, PostMessage, GetCursorPos

msvcrt.dllはVisual C++(マイクロソフトのC++コンパイラ)のランタイムライブラリの一つでC言語標準ライブラリを供給する。他の多くのランタイムライブラリと共に95(OSR2)以降のウィンドウズに標準添付されているためシステムDLLと見なすこともできよう。mingw-w64のランタイムライブラリは動的リンクおよび静的リンク共にこのDLLを利用するため、厳密にはmingw-w64はランタイムライブラリを完全に静的リンクできない。

MSYS2は/usr/binディレクトリにmsys-2.0.dllを置きPOSIX互換システムとウィンドウズを仲介させる。MSYS2のmsys-2.0.dllは(仮想的な)オペレーティングシステムを実現するシステムDLLと言える。

DLLの直接リンク

mingw-w64はインポートライブラリの代わりにDLLを直接指定することで、ロード時動的リンクする実行ファイルを作成できる。これは正確にはコンパイラが子プロセスとして起動するGNUリンカのWIN32(cygwin/mingw)拡張機能である。

DLLの実行時動的リンク

実行時動的リンクはDLLを実行ファイルロード時ではなく特定のAPI関数(LoadLibrary)実行時にロードする。他方、ロード時動的リンクと静的リンクはソースコードのコンパイルまで同じで、前者DLLインポートライブラリ(直接リンクなら前者DLL自身)あるいは後者スタティックリンクライブラリのどちらかをリンカで選択する。すなわちDLL実行時動的リンクはソースコードレベルから他と異なり、リンカによるリンクは関係ない。

覚え書き
ロード時動的リンクと実行時動的リンクについて用語は混乱するため整理しておく。
本サイト マイクロソフト(英語) マイクロソフト(日本語) 恐らく誤用
ロード時動的リンク Load-time dynamic linking Load-time動的リンク 動的リンク、静的ロード
実行時動的リンク Run-time dynamic linking 実行時動的リンク 動的ロード、動的読み込み
Run-time dynamic linkingの"Run-time"はランタイムライブラリの"ランタイム"とは何の関係も無い。

DLLの探索パス

実行ファイルは概ね以下の順番でロードするDLLを探索する。

  1. 実行ファイルと同じディレクトリ
  2. システムディレクトリ
  3. ウィンドウズディレクトリ
  4. カレントディレクトリ
  5. 環境変数PATHに設定されている先頭のディレクトリ
  6. 環境変数PATHに設定されている二番目ののディレクトリ
  7. ...

マイクロソフトのドキュメントはこれをもう少し複雑に定義するが、本サイトはこれで十分とする。32ビット/64ビットのシステムDLLを共存させるリダイレクションや明確にDLLを指定するサイドバイサイドがあるが、POSIXサブシステムは用いておらず本サイトも利用しない。

公式に記述するドキュメントは恐らく存在しないが、実行ファイルはDLL探索においてアーキテクチャの異なるDLLをスキップする。例えば64ビット実行ファイルはDLL探索で32ビットDLLを発見してもロードせず、ディレクトリ探索を続行し64ビットDLLを発見すればそちらをロードする。ただし32ビットDLL発見後に64ビットDLLを発見できなかった場合は32ビットDLLをロードしたものとしてエラーを報告する。

本サイトは32ビット/64ビットアプリケーションを統合開発環境で開発するため、PATH設定は十分な検討を必要とする。アーキテクチャの異なるDLLをスキップする機能は積極的に利用するが、非ドキュメンテッドの可能性が高く懸念が残る。