DLL とは

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

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

概要

この記事では、DLL の内容を説明する際に、動的リンク方法、DLL 依存関係、DLL エントリ ポイント、DLL 関数のエクスポート、および DLL トラブルシューティング ツールについて説明します。

この記事では、Dll と Microsoft のアセンブリの概要比較.NET Frameworkします。

Windows オペレーティング システムでは、オペレーティング システムの機能の多くが DLL によって提供されます。 さらに、これらの Windows オペレーティング システムでプログラムを実行すると、プログラムの機能の多くが 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 File Protection は有効なデジタル署名を探します。

  • プライベート DLL

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

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

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

依存関係のウォーカー

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

  • 依存関係のウォーカーは、不足している DLL をチェックします。
  • 依存関係のウォーカーは、無効なプログラム ファイルまたは DLL をチェックします。
  • 依存関係のウォーカーは、インポート関数とエクスポート関数が一致するチェックを行います。
  • 依存関係のウォーカーは、循環依存関係エラーをチェックします。
  • 依存関係の Walker は、モジュールが異なるオペレーティング システム用のため無効なモジュールをチェックします。

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

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

DLL ユニバーサル問題解決

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

  • Dlister.exe

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

  • Dcomp.exe

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

  • Dtxt2DB.exe

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

  • DlgDtxt2DB.exe

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

DLL ヘルプ データベース

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

DLL の開発

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

DLL の種類

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

読み込み時の動的リンク

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

実行時の動的リンク

実行時の動的リンクでは、アプリケーションは実行時に DLL を読み込む関数または関数 LoadLibrary LoadLibraryEx を呼び出します。 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 つのヘッダー ファイルと、エクスポート ステートメントとステートメントを分離するステートメント ifdef を使用 import します。

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

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

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

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

次のコードは 、Win32 ライブラリ プロジェクトの種類を使用してVisual C++で作成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 Application プロジェクトの例です。

// 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使用できます。

関連情報