Dll-quick-guide
DLL-はじめに
動的リンクは、実行時にアプリケーションをライブラリにリンクするメカニズムです。 ライブラリは独自のファイルに残り、アプリケーションの実行可能ファイルにコピーされません。 DLLは、アプリケーションの作成時ではなく、実行時にアプリケーションにリンクします。 DLLには、他のDLLへのリンクが含まれる場合があります。
多くの場合、DLLは .exe 、。drv *、。dll *などの異なる拡張子を持つファイルに配置されます。
DLLの利点
DLLファイルを持つことのいくつかの利点を以下に示します。
使用するリソースが少ない
DLLファイルは、メインプログラムと共にRAMに読み込まれません。必要でない限り、スペースを占有しません。 DLLファイルが必要になると、それが読み込まれて実行されます。 たとえば、Microsoft Wordのユーザーがドキュメントを編集している限り、RAMにプリンターDLLファイルは必要ありません。 ユーザーがドキュメントを印刷することを決定した場合、WordアプリケーションはプリンターDLLファイルをロードして実行します。
モジュラーアーキテクチャを促進する
DLLは、モジュール式プログラムの開発を促進するのに役立ちます。 複数の言語バージョンを必要とする大規模なプログラム、またはモジュラーアーキテクチャを必要とするプログラムの開発に役立ちます。 モジュラープログラムの例は、実行時に動的にロードできる多くのモジュールを備えたアカウンティングプログラムです。
簡単な展開とインストールを支援
DLL内の機能に更新または修正が必要な場合、DLLの展開とインストールでは、プログラムをDLLと再リンクする必要はありません。 さらに、複数のプログラムが同じDLLを使用する場合、それらすべてが更新または修正の恩恵を受けます。 この問題は、定期的に更新または修正されるサードパーティのDLLを使用すると、より頻繁に発生する可能性があります。
DLLリンケージがコンパイルの一部としてモジュール定義ファイルのIMPORTSセクションで指定されている場合、アプリケーションとDLLは他のDLLに自動的にリンクできます。 それ以外の場合は、Windows LoadLibrary関数を使用して明示的に読み込むことができます。
重要なDLLファイル
以下に挙げるのは、ユーザーがプログラミングのために知っておくべきいくつかの重要な dll ファイルです-
- COMDLG32.DLL -ダイアログボックスを制御します。
- GDI32.DLL -グラフィックの描画、テキストの表示、およびフォントの管理のための多数の機能が含まれています。
- KERNEL32.DLL -メモリおよびさまざまなプロセスの管理のための何百もの機能が含まれています。
- USER32.DLL -多数のユーザーインターフェイス関数が含まれています。 プログラムウィンドウの作成とそれらの相互の対話に関与します。
DLL-書き方
最初に、独自のDLLを開発する際に考慮すべき問題と要件について説明します。
DLLの種類
アプリケーションにDLLをロードすると、2つのリンク方法でエクスポートされたDLL関数を呼び出すことができます。 リンクの2つの方法は次のとおりです-
- ロード時の動的リンク、および
- 実行時の動的リンク。
ロード時の動的リンク
ロード時の動的リンクでは、アプリケーションはローカル関数などのエクスポートされたDLL関数を明示的に呼び出します。 ロード時の動的リンクを使用するには、アプリケーションをコンパイルおよびリンクするときに、ヘッダー(.h)ファイルとインポートライブラリ(.lib)ファイルを提供します。 これを行うと、リンカはDLLをロードし、ロード時にエクスポートされたDLL関数の場所を解決するために必要な情報をシステムに提供します。
ランタイム動的リンク
ランタイムダイナミックリンクでは、アプリケーションはLoadLibrary関数またはLoadLibraryEx関数のいずれかを呼び出して、実行時にDLLをロードします。 DLLが正常にロードされたら、GetProcAddress関数を使用して、エクスポートするDLL関数のアドレスを取得します。 ランタイムダイナミックリンクを使用する場合、インポートライブラリファイルは必要ありません。
次のリストは、ロード時の動的リンクと実行時の動的リンクを選択するためのアプリケーションの基準を説明しています-
- 起動パフォーマンス-アプリケーションの初期起動パフォーマンスが重要な場合は、ランタイムの動的リンクを使用する必要があります。
- 使いやすさ-ロード時の動的リンクでは、エクスポートされたDLL関数はローカル関数に似ています。 これらの関数を簡単に呼び出すことができます。
- アプリケーションロジック-ランタイムダイナミックリンクでは、アプリケーションは必要に応じて分岐して異なるモジュールをロードできます。 これは、複数言語バージョンを開発する場合に重要です。
DLLエントリポイント
DLLを作成するときに、オプションでエントリポイント関数を指定できます。 エントリポイント関数は、プロセスまたはスレッドが自身をDLLにアタッチするか、DLLからデタッチするときに呼び出されます。 エントリポイント関数を使用して、DLLの必要に応じてデータ構造を初期化または破棄できます。
さらに、アプリケーションがマルチスレッドの場合、スレッドローカルストレージ(TLS)を使用して、エントリポイント関数の各スレッドにプライベートなメモリを割り当てることができます。 次のコードは、DLLエントリポイント関数の例です。
BOOL APIENTRY DllMain(
HANDLE hModule, //Handle to DLL module
DWORD ul_reason_for_call,
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 ステートメントと ifdef ステートメントを持つ1つのヘッダーファイルを使用して、エクスポートステートメントとインポートステートメントを分離します。
モジュール定義ファイルを使用して、エクスポートされたDLL関数を宣言することもできます。 モジュール定義ファイルを使用する場合、エクスポートされたDLL関数にfunctionキーワードを追加する必要はありません。 モジュール定義ファイルで、DLLの LIBRARY ステートメントと EXPORTS ステートメントを宣言します。 次のコードは、定義ファイルの例です。
//SampleDLL.def
//
LIBRARY "sampleDLL"
EXPORTS
HelloWorld
サンプルDLLを書く
Microsoft Visual C ++ 6.0では、 Win32 Dynamic-Link Library プロジェクトタイプまたは* MFC AppWizard(dll)*プロジェクトタイプのいずれかを選択して、DLLを作成できます。
次のコードは、Win32 Dynamic-Link Libraryプロジェクトタイプを使用してVisual C ++で作成されたDLLの例です。
//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
サンプルDLLの呼び出し
次のコードは、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を検索します-
- アプリケーションフォルダー
- 現在のフォルダ
- Windowsシステムフォルダー( GetSystemDirectory 関数はWindowsシステムフォルダーのパスを返します)。
- Windowsフォルダー( GetWindowsDirectory 関数はWindowsフォルダーのパスを返します)。
DLL-登録
DLLを使用するには、レジストリに適切な参照を入力して登録する必要があります。 レジストリ参照が破損し、DLLの機能が使用できなくなることがあります。 DLLは、Start-Runを開き、次のコマンドを入力して再登録できます。
regsvr32 somefile.dll
このコマンドは、somefile.dllがPATHにあるディレクトリまたはフォルダーにあることを前提としています。 それ以外の場合は、DLLのフルパスを使用する必要があります。 以下に示すように、スイッチ "/u"を使用してDLLファイルを登録解除することもできます。
regsvr32/u somefile.dll
これは、サービスのオンとオフを切り替えるために使用できます。
DLL-ツール
DLLの問題のトラブルシューティングに役立ついくつかのツールが利用可能です。 それらのいくつかを以下で説明します。
依存関係ウォーカー
Dependency Walkerツール( depends.exe )は、プログラムで使用されているすべての依存DLLを再帰的にスキャンできます。 Dependency Walkerでプログラムを開くと、Dependency Walkerは次のチェックを実行します。
- 欠落しているDLLをチェックします。
- 無効なプログラムファイルまたはDLLをチェックします。
- インポート機能とエクスポート機能が一致することを確認します。
- 循環依存エラーをチェックします。
- モジュールが異なるオペレーティングシステム用であるため、無効なモジュールをチェックします。
Dependency Walkerを使用すると、プログラムが使用するすべてのDLLを文書化できます。 将来発生する可能性のあるDLLの問題を防止および修正するのに役立ちます。 Dependency Walkerは、Microsoft Visual Studio 6.0のインストール時に次のディレクトリにあります。
drive\Program Files\Microsoft Visual Studio\Common\Tools
DLL Universal Problem Solver
DLL Universal Problem Solver(DUPS)ツールは、DLL情報の監査、比較、文書化、および表示に使用されます。 次のリストは、DUPSツールを構成するユーティリティについて説明しています。
- Dlister.exe -このユーティリティは、コンピューター上のすべてのDLLを列挙し、テキストファイルまたはデータベースファイルに情報を記録します。
- Dcomp.exe -このユーティリティは、2つのテキストファイルにリストされているDLLを比較し、違いを含む3番目のテキストファイルを生成します。
- Dtxt2DB.exe -このユーティリティは、Dlister.exeユーティリティとDcomp.exeユーティリティを使用して作成されたテキストファイルをdllHellデータベースにロードします。
- DlgDtxt2DB.exe -このユーティリティは、Dtxt2DB.exeユーティリティのグラフィカルユーザーインターフェイス(GUI)バージョンを提供します。
DLL-ヒント
DLLを作成する際には、次のヒントに留意してください-
- 適切な呼び出し規則(Cまたはstdcall)を使用します。
- 関数に渡される引数の正しい順序に注意してください。
- 関数に直接渡される引数を使用して、配列のサイズを変更したり、文字列を連結したりしないでください。 渡すパラメータはLabVIEWデータであることに注意してください。 配列または文字列のサイズを変更すると、LabVIEWメモリに保存されている他のデータが上書きされてクラッシュする可能性があります。 LabVIEW配列ハンドルまたはLabVIEW文字列ハンドルを渡し、Visual C ++コンパイラまたはSymantecコンパイラを使用してDLLをコンパイルしている場合、配列のサイズを変更したり、文字列を連結できます。
- 関数に文字列を渡すときに、渡す文字列の正しいタイプを選択します。 CまたはPascalまたはLabVIEW文字列ハンドル。
- パスカル文字列の長さは255文字に制限されています。
- C文字列はNULLで終了します。 DLL関数が数値データをバイナリ文字列形式で返す場合(たとえば、GPIBまたはシリアルポート経由)、データ文字列の一部としてNULL値を返す場合があります。 このような場合、短い(8ビット)整数の配列を渡すことが最も信頼できます。
- データの配列または文字列を使用している場合、LabVIEWハンドルとして渡さない限り、関数によってバッファに配置された結果を保持するのに十分な大きさのバッファまたは配列を常に渡します。その場合、CINを使用してサイズを変更できますVisual C ++またはSymantecコンパイラの下で機能します。
- _stdcallを使用している場合は、モジュール定義ファイルのEXPORTSセクションにDLL関数をリストします。
- モジュール定義ファイルのEXPORTSセクションで他のアプリケーションが呼び出すDLL関数をリストするか、関数宣言に_declspec(dllexport)キーワードを含めます。
- C ++コンパイラを使用する場合、名前のマングリングを防ぐために、ヘッダーファイルでextern .C。\ {}ステートメントを使用して関数をエクスポートします。
- 独自のDLLを作成している場合、DLLが別のアプリケーションによってメモリにロードされている間はDLLを再コンパイルしないでください。 DLLを再コンパイルする前に、その特定のDLLを使用しているすべてのアプリケーションがメモリからアンロードされていることを確認してください。 DLL自体がメモリにロードされないようにします。 これを忘れて、コンパイラが警告しない場合、正しく再構築できない可能性があります。
- 別のプログラムでDLLをテストして、関数(およびDLL)が正しく動作することを確認します。 コンパイラのデバッガ、またはDLL内の関数を呼び出すことができる単純なCプログラムでテストすることは、DLLまたはLabVIEW関連の問題の可能性を特定するのに役立ちます。
DLL-例
DLLの記述方法と「Hello World」プログラムの作成方法を見てきました。 その例は、DLLを作成する基本的な概念についてのアイデアを与えているに違いありません。
ここでは、Delphi、Borland C 、VC を使用してDLLを作成する方法について説明します。
これらの例を一つずつ見ていきましょう。
- link:/dll/dll_delphi_example [Delphi内でDLLを作成して呼び出す方法]
- link:/dll/dll_borland_example [Borland C ++ Builder IDEからDLLを作成する]
- link:/dll/dll_vcpp_example [Microsoft Visual C ++ 6.0でDLLを作成する]