DLL とは

適用対象: なし

概要


ここでは、ダイナミックリンクライブラリ(DLL)と、DLLの使用時に発生するさまざまな問題について説明します。

次に、独自のDLLを開発するときに考慮する必要があるいくつかの高度な問題について説明します。 DLL の概要として、この記事では、動的なリンク方法、DLL の依存関係、DLL エントリポイント、DLL 関数のエクスポート、DLL のトラブルシューティングツールについて説明します。

この記事では、Microsoft .NET Framework アセンブリへの DLL の高度な比較について説明します。

はじめに


[適用]セクションに表示される Microsoft Windows オペレーティングシステムの場合、オペレーティングシステムの機能の多くは、ダイナミックリンクライブラリ(DLL )によって提供されます。 また、これらの Windows オペレーティングシステムの 1つでプログラムを実行すると、プログラムの多くの機能が DLL によって提供される可能性があります。 たとえば、一部のプログラムにはさまざまなモジュールが含まれており、プログラムの各モジュールは、DLL に含まれ、分散されています。

DLL を使用すると、コードのモジュール分割法、コードの再利用、効率的なメモリ使用、ディスクの空き領域の削減が容易になります。 したがって、オペレーティングシステムとプログラムの負荷が高速になり、コンピューターのディスクの空き領域が少なくなります。

プログラムが DLL を使用すると、依存関係が発生すると、プログラムが実行されないことがあります。 プログラムが DLL を使用すると、依存関係が作成されます。 別のプログラムがこの依存関係を上書きして中断すると、元のプログラムが正常に実行されない可能性があります。

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

詳細情報


DLL とは

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 の競合として認識されています。 下位互換性が適用されていない場合、プログラムは正常に実行されません。

次の一覧では、Microsoft Windows 2000 およびそれ以降の Windows オペレーティングシステムで導入された変更点について説明し、依存関係の問題を最小限に抑えるためのものを示します。
  • Windows ファイル保護 (WFP)
    Windows ファイル保護では、オペレーティングシステムは、許可されていないエージェントによってシステム DLLを更新または削除できません。 したがって、プログラムのインストールがシステム DLL として定義されている DLLを削除または更新しようとすると、Windowsファイル保護は有効なデジタル署名を検索します。
  • プライベート DLL
    プライベート DLL を使用すると、共有 DLL に加えられた変更からプログラムを分離できます。 プライベート DLL は、バージョン固有の情報または空の .local ファイルを使用して、プログラムで使用される DLL のバージョンを適用します。 プライベートDLLを使用するには、プログラムルートフォルダーで DLL を探します。 次に、新しいプログラムで、 DLL にバージョン固有の情報を追加します。 古いプログラムの場合は、空の .local ファイルを使用します。 各メソッドは、プログラムルートフォルダーにあるプライベート DLL を使用するようにオペレーティングシステムを指示します。

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

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

Dependency Walker

Dependency Walker ツールは、プログラムによって使用されるすべての依存 DLL を定期的にスキャンすることができます。 Dependency Walker でプログラムを開くと、依存関係ウォーカーによって次のチェックが行われます。
  • Dependency Walker は、見つからない DLL をチェックします。
  • Dependency Walker は、無効なプログラムファイルまたはDLLをチェックします。
  • Dependency Walker は、インポート機能とエクスポート関数が一致することを確認します。
  • Dependency Walker は循環依存関係エラーをチェックします。
  • Dependency Walker は、モジュールが別のオペレーティングシステムのものであるために無効のモジュールをチェックします。
Dependency Walker を使用することで、プログラムが使用するすべてのDLLを文書化できます。 これにより、将来発生する可能性のある DLL の問題を回避し、修正できます。 Dependency Walker は、 Microsoft Visual Studio 6.0 をインストールする際、次のディレクトリに位置しています。
drive\Program Files\Microsoft Visual Studio\Common\Tools

DLL ユニバーサル問題ソルバー

DLL のユニバーサル問題ソルバー( DUPS )ツールは、DLL 情報の監査、比較、記録、表示に使用されます。 次の一覧に、DUPS ツールを構成するユーティリティを示します。
  • Dlister.exe
    このユーティリティは、コンピューター上のすべてのDLLを列挙し、情報をテキストファイルまたはデータベースファイルに記録します。
  • Dcomp.exe
    このユーティリティは、2つのテキストファイルに含まれる DLL を比較し、相違点を含む 3 つ目のテキストファイルを生成します。
  • Dtxt2DB.exe
    このユーティリティは、 Dlister.exe ユーティリティと Dcomp.exe ユーティリティを使用して作成されたテキストファイルをdllHell データベースに読み込みます。
  • DlgDtxt2DB.exe
    このユーティリティでは、 Dtxt2DB.exe ユーティリティのグラフィックユーザーインターフェース ( GUI )バージョンが提供されています。
DUPS ツールの関連情報を参照するには、以下の「サポート技術情報」( Microsoft Knowledge Base )をクリックしてください。
247957 DUPS.exe を使用してDLLの互換性の問題を解決する

DLL ヘルプデータベース

DLL ヘルプデータベースは、Microsoft ソフトウェア製品によってインストールされる特定のバージョンのDLLを見つけるのに役立ちます。 DLL ヘルプデータベースの詳細については、次のマイクロソフト Web サイトを参照してください。

DLL 開発

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

DLL の種類

アプリケーションに DLL を読み込むと、2 つのメソッドを使用して、エクスポートされた DLL 関数を呼び出すことができます。 リンクの 2 つの方法は、動的リンクと実行時動的リンクの 2 つです。
Load-time 動的リンク
Load-time 動的なリンク付けでは、アプリケーションは、エクスポートされたDLL関数をローカル関数と同様に明示的に呼び出します。 load-time ダイナミックリンクを使用するには、アプリケーションをコンパイルおよびリンクするときにヘッダー( .h )ファイルとインポートライブラリ( .lib )ファイルを指定します。 これを行うと、ダイナミックリンクは DLL を読み込むために必要な情報をシステムに提供し、エクスポート時にエクスポートされた DLL 関数の場所を解決します。
実行時動的リンク
実行時の動的なリンクでは、アプリケーションは LoadLibrary 関数または LoadLibraryEx 関数を呼び出してDLLを実行時にロードします。 DLLが正常に読み込まれたら、 GetProcAddress 関数を使用して、呼び出すエクスポートしたDLL関数のアドレスを取得します。 実行時動的リンクを使用する場合、インポートライブラリファイルは必要ありません。

次のリストでは、load-time 動的リンクを使用する場合と、実行時動的リンクを使用する場合のアプリケーション条件について説明します。
  • 起動時のパフォーマンス
    アプリケーションの初期起動パフォーマンスが重要である場合は、実行時動的なリンクを使用する必要があります。
  • 使いやすさ
    load-time 動的リンクでは、エクスポートされた 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 値を返した場合、load-time 動的リンクを使用している場合、アプリケーションは起動しません。 実行時動的リンクを使用している場合は、個々の DLL だけが読み込まれます。

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

注意 マルチスレッドアプリケーションでは、データが破損しないように、DLL グローバルデータへのアクセスが同期するよう確認します。(スレッドセーフ)。 これを行うには、TLS を使用して各スレッドに固有のデータを提供します。

DLL 関数のエクスポート

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

関数キーワードを使用するには、エクスポートする各関数を次のキーワードで宣言する必要があります。
__declspec(dllexport)
書き出された DLL 関数をアプリケーションで使用するには、次のキーワードでインポートする各関数を宣言する必要があります。
__declspec(dllexport)
通常、定義ステートメントとインポートステートメントを区切るには、 定義 ステートメントと ifdef ステートメントを持つ 1 つのヘッダーファイルを使用します。

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

EXPORTS
HelloWorld

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

Microsoft Visual C++6.0 では、 Win32 Dynamic-Link Library プロジェクトの種類または、
MFC AppWizard(CSOM) プロジェクトの種類を選択して DLL を作成することができます。

次のコードは、 Visual C++ で作成された DLL の例です。
Win 32 Dynamic-Link Library プロジェクトの種類。
// 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 インポートライブラリをリンクする必要があります。

実行時の動的なリンクでは、次のコードと類似したコードを使用して、 SampleDLL.dll エクスポート 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 システムフォルダ

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

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

The .NET Framework アセンブリ

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

アセンブリファイルには、アセンブリマニフェスト、メタデータの種類、Microsoft Intermediate Language (MSIL) コード、その他のリソースが含まれます。 アセンブリマニフェストには、自己記述的なアセンブリのために必要なすべての情報を提供するアセンブリメタデータが含まれています。 アセンブリマニフェストには、次の情報が含まれます。
  • アセンブリ名
  • バージョン情報
  • カルチャ情報
  • 厳密な名前情報
  • ファイルのアセンブリ一覧
  • 参照情報を入力します。
  • 参照されるアセンブリおよび依存アセンブリ情報
アセンブリに含まれている MSIL コードを直接実行することはできません。 代わりに、MSIL のコード実行は CLR を通じて管理されます。 既定では、アセンブリを作成すると、アセンブリはアプリケーションはプライベートのものになります。 共有アセンブリを作成するには、アセンブリに厳密な名前を割り当て、アセンブリをグローバルアセンブリキャッシュに発行する必要があります。

以下に、Win 32 DLLの機能と比較したアセンブリの一部の機能を示します。
  • 自己記述
    アセンブリを作成すると、CLR に必要なすべての情報がアセンブリマニフェストに含まれます。 アセンブリマニフェストには、依存アセンブリのリストが含まれます。 したがって、CLRは、アプリケーションで使用される一貫したアセンブリセットを維持できます。 Win 32 DLLでは、共有 DLL を使用するときにアプリケーションで使用される DLLのセット間の整合性を維持できません。
  • バージョン管理
    アセンブリマニフェストでは、バージョン情報が CLR によって記録され、適用されます。 また、バージョンポリシーを使用すると、バージョン固有の利用状況を適用できます。 Win 32 DLLでは、バージョン管理をオペレーティングシステムでは適用できません。 その代わりに、DLLが下位互換性を備えていることを確認する必要があります。
  • 並行展開
    アセンブリは並行展開をサポートします。 1つのアプリケーションでアセンブリの1つのバージョンを使用でき、別のアプリケーションでは異なるバージョンのアセンブリを使用できます。 Windows 2000以降、並行展開は、アプリケーションフォルダーで DLL を見つけることでサポートされます。 また、Windowsファイル保護により、システムDLLが無許可のエージェントで上書きまたは置き換えられることがなくなります。
  • 内蔵と分離
    アセンブリを使用して開発されたアプリケーションは、コンピューター上で実行されている他のアプリケーションから内蔵および分離できます。 この機能は、影響のないインストールをするのに役立ちます。
  • 実行
    アセンブリは、アセンブリマニフェストで提供されるセキュリティ権限で実行され、CLRによって制御されます。
  • 言語非依存
    アセンブリは、サポートされている .NET 言語のいずれかを使用して開発できます。 たとえば、Microsoft Visual C#でアセンブリを開発し、Microsoft Visual Basic.NETプロジェクトでアセンブリを使用することができます。

関連情報


DLL および .NET Framework アセンブリの詳細については、次のマイクロソフト Web サイトを参照してください。
DLL の競合
http://msdn2.microsoft.com/ja-jp/library/ms811694.aspx

アプリケーションでの並列コンポーネント共有の実装
http://msdn2.microsoft.com/ja-jp/library/ms811700.aspx

Windows XP 用の分離されたアプリケーションおよび並行アセンブリの構築およびサービスの提供方法
http://msdn2.microsoft.com/ja-jp/library/ms997620.aspx

開発の単純化と .NET Framework とDLL 競合の解消
http://msdn2.microsoft.com/ja-jp/netframework/aa497268.aspx

.NET Framework 開発者ガイド アセンブリ
http://msdn2.microsoft.com/ja-jp/library/hk5f40ct(vs.71).aspx

実行時動的リンク
http://msdn2.microsoft.com/ja-jp/library/ms685090.aspx

スレッドローカルストレージ
http://msdn2.microsoft.com/ja-jp/library/ms686749.aspx

サポートを受ける

お問い合わせ

ディスカッションに参加する

コミュニティを依頼