Share via


リンク方式の使い分け

更新 : 2007 年 11 月

リンクには、暗黙的なリンクと明示的なリンクの 2 種類があります。

暗黙的リンク

アプリケーションのコードで DLL のエクスポート関数を呼び出すと、暗黙にリンクされます。DLL 関数を呼び出す実行形式のソース コードをコンパイルまたはアセンブルすると、オブジェクト コード内に外部関数への参照が生成されます。この外部参照を解決するには、アプリケーションをインポート ライブラリ (.lib) ファイルとリンクする必要があります。インポート ライブラリは、DLL の作成元が提供します。

インポート ライブラリには、DLL を読み込んで、DLL 内の関数呼び出しを実装するコードが含まれるだけです。リンカは、インポート ライブラリ内に外部関数を見つけると、その関数のコードは DLL 内にあるものと認識します。リンカは、単に DLL コードの場所を実行可能ファイルに記入することによって、外部参照を解決します。システムはプロセスの起動時にこの情報を利用します。

動的にリンクされた参照を含むプログラムが起動されると、プログラムの実行可能ファイル内の情報に従って、必要な DLL を探します。DLL が見つからないと、システムは処理を停止し、ダイアログ ボックスを表示して、エラーを報告します。見つかった場合は、DLL モジュールがプロセスのアドレス空間に割り当てられます。

DLL にエントリ ポイント関数 (初期化および終了コード用) がある場合、オペレーティング システムはその関数を呼び出します。エントリ ポイント関数に渡されるパラメータの 1 つは、DLL がプロセスにアタッチされようとしていることを示すコードになります。エントリ ポイント関数が TRUE を返さない場合、システムは処理を停止し、エラーを報告します。

最後に、システムはプロセスの実行可能コードを変更し、その DLL 関数の開始アドレスをセットします。

プログラム コードの残りの部分と同じように、DLL コードはプロセスの開始時にプロセスのアドレス空間に割り当てられますが、メモリに読み込まれるのはそれが必要とされたときです。結果として、これまでのバージョンの Windows で読み込みを制御するために .def ファイルで使用されていた PRELOAD および LOADONCALL コード属性は、不要になりました。

明示的リンク

暗黙的リンクは最も使いやすい方法なので、多くのアプリケーションは、暗黙的リンクを使います。しかし、明示的リンクが必要な場合もあります。ここでは、明示的リンクを使う一般的な理由について説明します。

  • アプリケーションは、読み込む必要のある DLL の名前を実行時に初めて認識します。たとえば、アプリケーションは、DLL の名前とエクスポート関数を設定ファイルから取得しなければならない場合があります。

  • DLL がプロセスの起動時に見つからない場合、暗黙的なリンクを使うプロセスは、オペレーティング システムによって停止されます。同じ状況でも、明示的リンクを使うプロセスは停止されずに、エラーからの回復を試行します。たとえば、プロセスがユーザーにエラーを通知して、ユーザーに DLL への別のパスを指定させることができます。

  • プロセスにリンクする DLL の DllMain 関数が失敗する場合にも、暗黙的リンクを使うプロセスは停止されます。同じ状況でも、明示的リンクを使うプロセスは停止されません。

  • Windows は、アプリケーションの読み込み時にすべての DLL を読み込むため、暗黙的に多くの DLL とリンクするアプリケーションは、起動に時間がかかることがあります。起動時のパフォーマンスを向上するには、アプリケーションは読み込み直後に必要な DLL を暗黙的にリンクし、その他の DLL については必要なときに明示的にリンクするように待機させることができます。

  • 明示的リンクの場合、アプリケーションとインポート ライブラリをリンクする必要はありません。DLL 内の変更によってエクスポート序数が変更される場合、明示的リンクを使うアプリケーションをリンクし直す必要はありません (序数値ではなく関数の名前を使って GetProcAddress を呼び出すと仮定した場合)。他方、暗黙的リンクを使うアプリケーションは、新しいインポート ライブラリとリンクし直す必要があります。

明示的リンクの欠点は、次の 2 つです。

  • DLL が DllMain エントリ ポイント関数を持つ場合、オペレーティング システムは LoadLibrary を呼び出したスレッドのコンテキスト内で、DllMain 関数を呼び出します。LoadLibrary の前回の呼び出しに対応する FreeLibrary 関数が呼び出されていないために、DLL が既にプロセスにアタッチされている場合は、エントリ ポイント関数は呼び出されません。また、DLL が DllMain 関数を使って、プロセスの各スレッドの初期化を実行している場合、明示的リンクによって問題が発生することがあります。LoadLibrary (または AfxLoadLibrary) が呼び出される時点で、既存のスレッドが初期化されていないからです。

  • DLL が静的範囲のデータを __declspec(thread) として宣言する場合、明示的リンクでは保護違反が発生することがあります。DLL が LoadLibrary によって読み込まれる場合、コードがこのデータを参照すると、保護違反の原因になることがあります。静的範囲のデータには、グローバル スタティック アイテムとローカル スタティック アイテムの両方が含まれます。このため、DLL の作成時には、スレッド ローカル ストレージの利用を避けるか、エラー発生の可能性について DLL のユーザーに通知する (動的読み込みを試行する場合) 必要があります。

目的に合ったトピックをクリックしてください

さらに詳しくは次のトピックをクリックしてください

参照

概念

DLL と実行形式のリンク