DLL とは

この記事では、ダイナミック リンク ライブラリ (DLL) とは何か、および DLL を使用するときに発生する可能性があるさまざまな問題について説明します。 また、独自の DLL を開発するときに考慮する必要があるいくつかの高度な問題も説明します。

元の製品バージョン:   Windows 10 - すべてのエディション
元の KB 番号:   815065

まとめ

この記事では、DLL とは何かを説明する際に、ダイナミック リンク メソッド、DLL の依存関係、DLL エントリ ポイント、DLL 関数のエクスポート、および DLL トラブルシューティング ツールについて説明します。

この記事では、DLL と Microsoft .NET Framework アセンブリの比較を完了します。

Windows オペレーティング システムでは、オペレーティング システムの機能の多くが DLL によって提供されます。 さらに、これらの Windows オペレーティング システムの 1 つでプログラムを実行すると、プログラムの機能の多くが DLL によって提供される場合があります。 たとえば、一部のプログラムには多数の異なるモジュールが含まれている場合や、プログラムの各モジュールが DLL に格納され、DLL に配布されている場合があります。

DLL を使用すると、コードのモジュール化、コードの再利用、効率的なメモリ使用量、およびディスク領域の削減を促進できます。 そのため、オペレーティング システムとプログラムの読み込み速度が速く、実行速度が速く、コンピューターのディスク領域が少なくなります。

プログラムが DLL を使用している場合、依存関係と呼ばれる問題が原因でプログラムが実行されない可能性があります。 プログラムで DLL を使用すると、依存関係が作成されます。 別のプログラムが上書きしてこの依存関係を壊した場合、元のプログラムが正常に実行されない可能性があります。

.NET Framework の導入により、ほとんどの依存関係の問題はアセンブリを使用することで排除されました。

詳細情報

DLL は、複数のプログラムで同時に使用できるコードとデータを含むライブラリです。 たとえば、Windows オペレーティング システムでは、Comdlg32 DLL は一般的なダイアログ ボックス関連の機能を実行します。 各プログラムは、この DLL に含まれる機能を使用して、[開く] ダイアログ ボックス 実装できます。 コードの再利用と効率的なメモリ使用量の促進に役立ちます。

DLL を使用すると、プログラムを個別のコンポーネントにモジュール化できます。 たとえば、会計プログラムをモジュールで販売できます。 モジュールがインストールされている場合、各モジュールは実行時にメイン プログラムに読み込まれます。 モジュールは別々なので、プログラムの読み込み時間が短縮されます。 また、モジュールは、その機能が要求された場合にのみ読み込まれます。

さらに、プログラムの他の部分に影響を与えることなく、各モジュールに更新プログラムを適用する方が簡単です。 たとえば、給与プログラムを利用している場合、税率は毎年変更されます。 これらの変更が DLL に分離されている場合は、プログラム全体を再びビルドまたはインストールすることなく更新プログラムを適用できます。

次の一覧では、Windows オペレーティング システムで DLL として実装されるファイルの一部について説明します。

  • ActiveX コントロール (.ocx) ファイル

    カレンダー コントロールのActiveX、カレンダーから日付を選択できるカレンダー コントロールがあります。

  • コントロール パネル (.cpl) ファイル

    .cpl ファイルの例として、コントロール パネルにある項目があります。 各項目は専用の DLL です。

  • デバイス ドライバー (.drv) ファイル

    デバイス ドライバーの例として、プリンターへの印刷を制御するプリンター ドライバーがあります。

DLL の利点

プログラムで DLL を使用する場合に提供される利点の一部を次に示します。

  • 使用するリソースが少ない

    複数のプログラムが同じ関数ライブラリを使用している場合、DLL はディスクと物理メモリに読み込まれるコードの重複を減らします。 フォアグラウンドで実行されているプログラムだけでなく、Windows オペレーティング システムで実行されている他のプログラムのパフォーマンスにも大きな影響を与える可能性があります。

  • モジュール化されたアーキテクチャの促進

    DLL はモジュール化されたプログラムの開発を促進するのに役立ちます。 複数の言語バージョンを必要とする大規模なプログラムや、モジュール化されたアーキテクチャを必要とするプログラムを開発するのに役立ちます。 モジュール化されたプログラムの例として、実行時に動的に読み込み可能なモジュールが多数含まれる会計プログラムがあります。

  • 展開とインストールを容易にする

    DLL 内の関数に更新プログラムまたは修正プログラムが必要な場合、DLL の展開とインストールではプログラムを DLL と再リンクする必要はありません。 さらに、複数のプログラムが同じ DLL を使用している場合、複数のプログラムはすべて更新プログラムまたは修正プログラムのメリットを受ける可能性があります。 この問題は、定期的に更新または修正されるサード パーティ製の DLL を使用する場合に発生する頻度が高い場合があります。

DLL の依存関係

プログラムまたは DLL が別の DLL で DLL 関数を使用すると、依存関係が作成されます。 プログラムは自己格納型ではなくなったので、依存関係が壊れているとプログラムに問題が発生する可能性があります。 たとえば、次のいずれかの操作が行われると、プログラムが実行されない可能性があります。

  • 依存 DLL が新しいバージョンにアップグレードされます。
  • 依存 DLL は固定されています。
  • 依存 DLL は以前のバージョンで上書きされます。
  • 依存 DLL がコンピューターから削除されます。

これらのアクションは、DLL の競合と呼ばれる機能です。 下位互換性が適用されていないと、プログラムが正常に実行されない可能性があります。

次の一覧では、依存関係の問題を最小限に抑えるために Windows 2000 以降の Windows オペレーティング システムで導入された変更について説明します。

  • Windows ファイル保護

    Windows ファイル保護では、オペレーティング システムは承認されていないエージェントによってシステム DLL が更新または削除されるのを防止します。 プログラムのインストールで、システム DLL として定義されている DLL を削除または更新しようとすると、Windows ファイル保護は有効なデジタル署名を探します。

  • プライベート DLL

    プライベート DLL を使用すると、共有 DLL に加えた変更からプログラムを分離できます。 プライベート DLL は、バージョン固有の情報または空のファイルを使用して、プログラムによって使用される DLL のバージョン .local を強制します。 プライベート DLL を使用するには、プログラムのルート フォルダーで DLL を探します。 次に、新しいプログラムの場合は、バージョン固有の情報を DLL に追加します。 古いプログラムの場合は、空のファイルを使用 .local します。 各メソッドは、プログラムのルート フォルダーにあるプライベート DLL を使用するオペレーティング システムに指示します。

DLL トラブルシューティング ツール

DLL の問題のトラブルシューティングに役立つツールがいくつか用意されています。 これらのツールの一部を次に示します。

Dependency Walker

Dependency Walker ツールは、プログラムで使用しているすべての依存 DLL を再帰的にスキャンできます。 Dependency Walker でプログラムを開いた場合、Dependency Walker は次のチェックを実行します。

  • 依存関係の Walker は、DLL が見つからないか確認します。
  • Dependency Walker は、無効なプログラム ファイルまたは DLL をチェックします。
  • インポート関数とエクスポート関数が一致する依存関係 Walker チェック。
  • 依存関係の Walker は循環依存関係エラーをチェックします。
  • 依存関係 Walker は、モジュールが別のオペレーティング システム用のため、無効なモジュールをチェックします。

Dependency Walker を使用すると、プログラムで使用しているすべての DLL を文書化できます。 将来発生する可能性のある DLL の問題の防止と修正に役立つ場合があります。 Dependency Walker は、6.0 をインストールするときに次Visual Studioにあります。

drive\Program Files\Microsoft Visual Studio\Common\Tools

DLL Universal Problem Solver

DLL ユニバーサル問題解決ツール (DUPS) を使用して、DLL 情報の監査、比較、文書化、表示を行います。 DUPS ツールを構成するユーティリティの一覧を次に示します。

  • Dlister.exe

    このユーティリティは、コンピューター上のすべての DLL を列挙し、その情報をテキスト ファイルまたはデータベース ファイルに記録します。

  • Dcomp.exe

    このユーティリティは、2 つのテキスト ファイルにリストされている DLL を比較し、違いを含む 3 番目のテキスト ファイルを生成します。

  • Dtxt2DB.exe

    このユーティリティは、Dlister.exe ユーティリティと Dcomp.exe ユーティリティを使用して作成されたテキスト ファイルを dllHell データベースに読み込む。

  • DlgDtxt2DB.exe

    このユーティリティは、グラフィカル ユーザー インターフェイス (GUI) バージョンの Dtxt2DB.exeします。

DLL ヘルプ データベース

DLL ヘルプ データベースは、Microsoft ソフトウェア製品によってインストールされる DLL の特定のバージョンを見つけるのに役立ちます。

DLL 開発

このセクションでは、独自の DLL を開発するときに考慮する必要がある問題と要件について説明します。

DLL の種類

アプリケーションで DLL を読み込む場合、2 つのリンク メソッドを使用してエクスポートされた DLL 関数を呼び出します。 リンクの 2 つの方法は、読み込み時のダイナミック リンクと実行時ダイナミック リンクです。

読み込み時の動的リンク

読み込み時の動的リンクでは、アプリケーションはローカル関数のようなエクスポートされた DLL 関数を明示的に呼び出します。 読み込み時の動的リンクを使用するには、アプリケーションをコンパイルしてリンクするときに、ヘッダー (.h) ファイルとインポート ライブラリ (.lib) ファイルを指定します。 これを行う場合、リンカーは、DLL を読み込み、読み込み時にエクスポートされた DLL 関数の場所を解決するために必要な情報をシステムに提供します。

実行時の動的リンク

実行時のダイナミック リンクでは、アプリケーションは実行時に関数または関数を呼び出して LoadLibrary LoadLibraryEx DLL を読み込む。 DLL が正常に読み込まれた後、この関数を使用して、呼び出すエクスポートされた DLL 関数 GetProcAddress のアドレスを取得します。 実行時ダイナミック リンクを使用する場合は、インポート ライブラリ ファイルは必要ではありません。

次の一覧では、読み込み時ダイナミック リンクを使用する場合と実行時ダイナミック リンクを使用する場合のアプリケーション条件について説明します。

  • スタートアップ パフォーマンス

    アプリケーションの初期起動時のパフォーマンスが重要な場合は、実行時ダイナミック リンクを使用する必要があります。

  • 使いやすさ

    読み込み時のダイナミック リンクでは、エクスポートされた DLL 関数はローカル関数と同様です。 これにより、これらの関数の呼び出しが簡単になります。

  • アプリケーション ロジック

    実行時の動的リンクでは、アプリケーションは分岐して、必要に応じて異なるモジュールを読み込む可能性があります。 複数言語バージョンを開発する場合は重要です。

DLL エントリ ポイント

DLL を作成するときに、必要に応じてエントリ ポイント関数を指定できます。 エントリ ポイント関数は、プロセスまたはスレッドが自身を DLL にアタッチするか、DLL から自身をデタッチするときに呼び出されます。 エントリ ポイント関数を使用して、データ構造を初期化したり、DLL の要求に応じてデータ構造を破棄することができます。 さらに、アプリケーションがマルチスレッドの場合は、スレッド ローカル ストレージ (TLS) を使用して、エントリ ポイント関数の各スレッドにプライベートなメモリを割り当てできます。 次のコードは、DLL エントリ ポイント関数の例です。

BOOL APIENTRY DllMain(
HANDLE hModule,// Handle to DLL module
DWORD ul_reason_for_call,// Reason for calling function
LPVOID lpReserved ) // Reserved
{
    switch ( ul_reason_for_call )
    {
        case DLL_PROCESS_ATTACHED: // A process is loading the DLL.
        break;
        case DLL_THREAD_ATTACHED: // A process is creating a new thread.
        break;
        case DLL_THREAD_DETACH: // A thread exits normally.
        break; case DLL_PROCESS_DETACH: // A process unloads the DLL.
        break;
    }
    return TRUE;
}

エントリ ポイント関数が FALSE 値を返す場合、読み込み時の動的リンクを使用している場合、アプリケーションは起動しません。 実行時ダイナミック リンクを使用している場合は、個々の DLL だけが読み込みされません。

エントリ ポイント関数は単純な初期化タスクのみを実行し、他の DLL の読み込み関数や終了関数を呼び出さすべきではありません。 たとえば、エントリ ポイント関数では、関数または関数を直接または間接的に呼び LoadLibrary 出す LoadLibraryEx 必要はありません。 また、プロセスが終了するときに FreeLibrary 関数を呼び出す必要はありません。

注意

マルチスレッド アプリケーションでは、データ破損の可能性を回避するために、DLL グローバル データへのアクセスが同期 (スレッド セーフ) であることを確認します。 これを行うには、TLS を使用してスレッドごとに一意のデータを提供します。

DLL 関数をエクスポートする

DLL 関数をエクスポートするには、エクスポートされた DLL 関数に関数キーワードを追加するか、エクスポートされた DLL 関数を一覧表示するモジュール定義 (.def) ファイルを作成します。

関数キーワードを使用するには、エクスポートする各関数を次のキーワードで宣言する必要があります。
__declspec(dllexport)

エクスポートされた DLL 関数をアプリケーションで使用するには、インポートする各関数を次のキーワードで宣言する必要があります。 __declspec(dllimport)

通常は、define ステートメントを含む 1 つのヘッダー ファイルと、export ステートメントとステートメントを分離する ifdef ステートメントを使用 import します。

また、モジュール定義ファイルを使用して、エクスポートされた DLL 関数を宣言できます。 モジュール定義ファイルを使用する場合、エクスポートされた DLL 関数に関数キーワードを追加する必要はありません。 モジュール定義ファイルで、DLL の LIBRARY ステートメントと EXPORTS ステートメントを宣言します。 次のコードは、定義ファイルの例です。

// SampleDLL.def
//
LIBRARY "sampleDLL"
EXPORTS HelloWorld

サンプル DLL とアプリケーション

Visual C++ 6.0 では 、Win32 Dynamic-Link ライブラリ プロジェクトの種類または MFC AppWizard (dll) プロジェクトの種類を選択して DLL を作成できます。

次のコードは、Visual C++ で Win32 ライブラリ プロジェクトの種類を使用して作成された DLL のDynamic-Linkです。

// SampleDLL.cpp
//

#include "stdafx.h"
#define EXPORTING_DLL
#include "sampleDLL.h"
BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved
)
{
    return TRUE;
}

void HelloWorld()
{
    MessageBox( NULL, TEXT("Hello World"), TEXT("In a DLL"), MB_OK);
}

// File: SampleDLL.h
//
#ifndef INDLL_H
    #define INDLL_H
    #ifdef EXPORTING_DLL
        extern __declspec(dllexport) void HelloWorld();
    #else
        extern __declspec(dllimport) void HelloWorld();
    #endif

#endif

次のコードは、SampleDLL DLL でエクスポートされた DLL 関数を呼び出す Win32 アプリケーション プロジェクトの例です。

// SampleApp.cpp
//
#include "stdafx.h"
#include "sampleDLL.h"
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    HelloWorld();
    return 0;
}

注意

読み込み時の動的リンクでは、SampleDLL プロジェクトのビルド時に作成される SampleDLL.lib インポート ライブラリをリンクする必要があります。

実行時のダイナミック リンクでは、次のコードに似たコードを使用して、エクスポートされた DLL 関数SampleDLL.dll呼び出します。

...
typedef VOID (*DLLPROC) (LPTSTR);
...
HINSTANCE hinstDLL;
DLLPROC HelloWorld;
BOOL fFreeDLL;

hinstDLL = LoadLibrary("sampleDLL.dll");
if (hinstDLL != NULL)
{
    HelloWorld = (DLLPROC) GetProcAddress(hinstDLL, "HelloWorld");
    if (HelloWorld != NULL)
        (HelloWorld);
    fFreeDLL = FreeLibrary(hinstDLL);
}
...

SampleDLL アプリケーションをコンパイルしてリンクすると、Windows オペレーティング システムは SampleDLL DLL を次の順序で検索します。

  1. アプリケーション フォルダー

  2. 現在のフォルダー

  3. Windows システム フォルダー

    注意

    GetSystemDirectory 関数は、Windows システム フォルダーのパスを返します。

  4. Windows フォルダー

    注意

    GetWindowsDirectory 関数は、Windows フォルダーのパスを返します。

.NET Framework アセンブリ

.NET と .NET Framework の導入により、DLL に関連する問題の多くがアセンブリを使用して排除されました。 アセンブリは、.NET 共通言語ランタイム (CLR) の制御下で実行される機能の論理ユニットです。 アセンブリは、物理的に .dll ファイルまたは .exe ファイルとして存在します。 ただし、内部的には、アセンブリは Microsoft Win32 DLL とは異なります。

アセンブリ ファイルには、アセンブリ マニフェスト、型メタデータ、Microsoft 中間言語 (MSIL) コード、その他のリソースが含まれます。 アセンブリ マニフェストには、アセンブリの自己説明に必要なすべての情報を提供するアセンブリ メタデータが含まれています。 次の情報がアセンブリ マニフェストに含まれています。

  • アセンブリ名
  • バージョン情報
  • カルチャ情報
  • 強い名前の情報
  • ファイルのアセンブリ リスト
  • 型参照情報
  • 参照されるアセンブリ情報と依存アセンブリ情報

アセンブリに含まれる MSIL コードを直接実行することはできません。 代わりに、MSIL コードの実行は CLR によって管理されます。 既定では、アセンブリを作成すると、アセンブリはアプリケーションに対してプライベートになります。 共有アセンブリを作成するには、アセンブリに強力な名前を割り当て、グローバル アセンブリ キャッシュでアセンブリを発行する必要があります。

次に、Win32 DLL の機能と比較したアセンブリの機能の一部を示します。

  • 自己説明

    アセンブリを作成すると、CLR がアセンブリを実行するために必要なすべての情報がアセンブリ マニフェストに含まれます。 アセンブリ マニフェストには、依存アセンブリのリストが含まれます。 したがって、CLR は、アプリケーションで使用されるアセンブリの一貫したセットを維持できます。 Win32 DLL では、共有 DLL を使用するときにアプリケーションで使用される DLL のセット間の整合性を維持できません。

  • バージョン管理

    アセンブリ マニフェストでは、バージョン情報が記録され、CLR によって適用されます。 さらに、バージョン ポリシーを使用すると、バージョン固有の使用法を適用できます。 Win32 DLL では、バージョン管理をオペレーティング システムで適用できない。 DLL が下位互換性を持っている必要があります。

  • サイド バイ サイド展開

    アセンブリは、サイド バイ サイド展開をサポートします。 1 つのアプリケーションで 1 つのバージョンのアセンブリを使用し、別のアプリケーションで別のバージョンのアセンブリを使用できます。 Windows 2000 から、アプリケーション フォルダー内に DLL を配置することで、サイド バイ サイド展開がサポートされています。 さらに、Windows ファイル保護は、システム DLL が承認されていないエージェントによって上書きまたは置き換えられるのを防ぐことができます。

  • 自己格納と分離

    アセンブリを使用して開発されたアプリケーションは、自己格納型で、コンピューター上で実行されている他のアプリケーションから分離できます。 この機能は、影響を受けないインストールの作成に役立ちます。

  • 実行

    アセンブリは、アセンブリ マニフェストで提供され、CLR によって制御されるセキュリティ アクセス許可の下で実行されます。

  • 言語に依存しない

    アセンブリは、サポートされている .NET 言語のいずれかを使用して開発できます。 たとえば、Microsoft Visual C# でアセンブリを開発し、.NET プロジェクトの Visual Basic使用できます。

関連情報