ダイナミック リンク ライブラリ (DLL) への省略可能なエントリ ポイント。 システムは、プロセスまたはスレッドを開始または終了するときに、プロセスの最初のスレッドを使用して、読み込まれた DLL ごとにエントリ ポイント関数を呼び出します。 システムは、 LOADLibrary 関数と FreeLibrary 関数を使用して読み込みまたはアンロードされるときに、DLL のエントリ ポイント関数も呼び出します。
Warning
DLL のエントリ ポイントで安全に実行できる処理には大きな制限があります。 DllMain で呼び出すのが安全でない特定のWindows API の一般的なベスト プラクティスを参照してください。 最も単純な初期化以外にも必要である場合は、DLL の初期化関数でそれを実行します。 DllMain の実行後、および DLL 内の他の関数を呼び出す前に、アプリケーションに初期化関数の呼び出しを要求できます。
例
BOOL WINAPI DllMain(
HINSTANCE hinstDLL, // handle to DLL module
DWORD fdwReason, // reason for calling function
LPVOID lpvReserved ) // reserved
{
// Perform actions based on the reason for calling.
switch( fdwReason )
{
case DLL_PROCESS_ATTACH:
// Initialize once for each new process.
// Return FALSE to fail DLL load.
break;
case DLL_THREAD_ATTACH:
// Do thread-specific initialization.
break;
case DLL_THREAD_DETACH:
// Do thread-specific cleanup.
break;
case DLL_PROCESS_DETACH:
if (lpvReserved != nullptr)
{
break; // do not do cleanup if process termination scenario
}
// Perform any necessary cleanup.
break;
}
return TRUE; // Successful DLL_PROCESS_ATTACH.
}
Dynamic-Link ライブラリ Entry-Point 関数の例を次 に示します。
構文
BOOL WINAPI DllMain(
_In_ HINSTANCE hinstDLL,
_In_ DWORD fdwReason,
_In_ LPVOID lpvReserved
);
Parameters
-
hinstDLL [in]
-
DLL モジュールへのハンドル。 値は DLL のベース アドレスです。 DLL の HINSTANCE は DLL の HMODULE と同じであるため、モジュール ハンドルを必要とする関数の呼び出しで hinstDLL を使用できます。
-
fdwReason [in]
-
DLL エントリ ポイント関数が呼び出されている理由を示す理由コード。 このパラメーターには、次のいずれかの値を指定できます。
価値 意味 - DLL_PROCESS_ATTACH
- 1
プロセスの起動の結果または LoadLibrary の呼び出しの結果として、DLL が現在のプロセスの仮想アドレス空間に読み込まれます。 DLL は、この機会を使用して任意のインスタンス データを初期化したり 、TlsAlloc 関数を使用してスレッド ローカル ストレージ (TLS) インデックスを割り当てたりすることができます。
lpvReserved パラメーターは、DLL が静的または動的に読み込まれているかどうかを示します。- DLL_PROCESS_DETACH
- 0
DLL が正常に読み込まれなかったか、参照カウントが 0 に達したために、呼び出し元プロセスの仮想アドレス空間から DLL がアンロードされています (プロセスは LoadLibrary を呼び出すたびに 1 回、終了したか FreeLibrary と呼ばれます)。
lpvReserved パラメーターは、FreeLibrary 呼び出し、読み込みの失敗、またはプロセス終了の結果として DLL がアンロードされているかどうかを示します。
DLL は、この機会を使用して TlsFree 関数を呼び出して、 TlsAlloc を使用して割り当てられた TLS インデックスを解放し、スレッド ローカル データを解放できます。
DLL_PROCESS_DETACH通知を受け取るスレッドは、必ずしもDLL_PROCESS_ATTACH通知を受け取ったスレッドと同じとは限らないことに注意してください。- DLL_THREAD_ATTACH
- 2
現在のプロセスでは、新しいスレッドが作成されています。 これが発生すると、現在プロセスにアタッチされているすべての DLL のエントリ ポイント関数が呼び出されます。 呼び出しは、新しいスレッドのコンテキストで行われます。 DLL は、この機会を使用してスレッドの TLS スロットを初期化できます。 DLL_PROCESS_ATTACHで DLL エントリ ポイント関数を呼び出すスレッドは、DLL_THREAD_ATTACHを持つ DLL エントリ ポイント関数を呼び出しません。
DLL のエントリ ポイント関数は、DLL がプロセスによって読み込まれた後に作成されたスレッドによってのみ、この値で呼び出されることに注意してください。 LoadLibrary を使用して DLL を読み込む場合、既存のスレッドは新しく読み込まれた DLL のエントリ ポイント関数を呼び出しません。- DLL_THREAD_DETACH
- 3
スレッドが正常に終了しています。 DLL が割り当てられたメモリへのポインターを TLS スロットに格納している場合は、この機会を使用してメモリを解放する必要があります。 システムは、現在読み込まれているすべての DLL のエントリ ポイント関数をこの値で呼び出します。 呼び出しは、終了スレッドのコンテキストで行われます。 -
lpvReserved [in]
-
fdwReason がDLL_PROCESS_ATTACH場合、lpvReserved は動的読み込みの場合は NULL、静的読み込みの場合は NULL 以外です。
fdwReason がDLL_PROCESS_DETACH場合、FreeLibrary が呼び出された場合、または DLL の読み込みが失敗した場合は lpvReserved は NULL になり、プロセスが終了している場合は NULL 以外になります。
値を返す
システムがDLL_PROCESS_ATTACH値を使用して DllMain 関数を呼び出すと、関数は成功した場合は TRUE を返し、初期化に失敗した場合は FALSE を返します。 プロセスが LoadLibrary 関数を使用しているために DllMain が呼び出されたときに戻り値が FALSE の場合、LoadLibrary は NULL を返します。 (システムはすぐにDLL_PROCESS_DETACHを使用してエントリ ポイント関数を呼び出し、DLL をアンロードします)。プロセスの初期化中に DllMain が呼び出されたときに戻り値が FALSE の場合、プロセスはエラーで終了します。 拡張エラー情報を取得するには、 GetLastError を呼び出します。
システムが dllMain 関数を DLL_PROCESS_ATTACH 以外の値で呼び出すと、戻り値は無視されます。
Remarks
DllMain は、ライブラリ定義関数名のプレースホルダーです。 DLL をビルドするときに使用する実際の名前を指定する必要があります。 詳細については、開発ツールに含まれているドキュメントを参照してください。
初期プロセスの起動時または LoadLibrary の呼び出し後、システムは読み込まれた DLL の一覧をスキャンしてプロセスを確認します。 DLL_PROCESS_ATTACH値でまだ呼び出されていない DLL ごとに、システムは DLL のエントリ ポイント関数を呼び出します。 この呼び出しは、プロセスのプライマリ スレッドや LoadLibrary を呼び出したスレッドなど、プロセス アドレス空間の変更の原因となったスレッドのコンテキストで行われます。 エントリ ポイントへのアクセスは、プロセス全体でシステムによってシリアル化されます。 DllMain 内のスレッドはローダー ロックを保持するため、追加の DLL を動的に読み込んだり初期化したりすることはできません。
DLL のエントリ ポイント関数は、 DLL_PROCESS_ATTACH 通知の後に FALSE を返す場合は、 DLL_PROCESS_DETACH 通知を受け取り、DLL は直ちにアンロードされます。 ただし、 DLL_PROCESS_ATTACH コードが例外をスローした場合、エントリ ポイント関数は DLL_PROCESS_DETACH 通知を受け取りません。
エントリ ポイント関数がスレッドの DLL_THREAD_ATTACH で呼び出されなかった場合でも、終了スレッドに対してエントリ ポイント関数が呼び出される場合があります。
- スレッドはプロセスの最初のスレッドであるため、システムは DLL_PROCESS_ATTACH 値を持つエントリ ポイント関数を呼び出しました。
- LoadLibrary 関数の呼び出しが行われたときにスレッドは既に実行されているため、システムはエントリ ポイント関数を呼び出しませんでした。
DLL の読み込みの失敗、プロセスの終了、または FreeLibrary の呼び出しの結果として DLL がプロセスからアンロードされた場合、システムはプロセスの個々のスレッドの DLL_THREAD_DETACH 値を使用して DLL のエントリ ポイント関数を呼び出しません。 DLL は 、DLL_PROCESS_DETACH 通知のみを送信します。 DLL は、DLL に認識されているすべてのスレッドのすべてのリソースをクリーンアップするこの機会を利用できます。
DLL_PROCESS_DETACHを処理する場合、DLL は DLL が動的にアンロードされている場合にのみ、ヒープ メモリなどのリソースを解放する必要があります (lpvReserved パラメーターは NULL です)。 プロセスが終了している場合 ( lpvReserved パラメーターが NULL でない場合)、現在のスレッドを除くプロセス内のすべてのスレッドは既に終了しているか、 ExitProcess 関数の呼び出しによって明示的に終了されているため、ヒープなどの一部のプロセス リソースが不整合な状態になる可能性があります。 この場合、DLL がリソースをクリーンアップしても安全ではありません。 代わりに、DLL はオペレーティング システムがメモリを解放できるようにする必要があります。
TerminateProcess または TerminateJobObject を呼び出してプロセスを終了した場合、そのプロセスの DLL はDLL_PROCESS_DETACH通知を受け取りません。 TerminateThread を呼び出してスレッドを終了した場合、そのスレッドの DLL はDLL_THREAD_DETACH通知を受け取りません。
エントリ ポイント関数は、単純な初期化タスクまたは終了タスクのみを実行する必要があります。 LOADLibrary 関数または LoadLibraryEx 関数 (またはこれらの関数を呼び出す関数) を呼び出してはなりません。これは、DLL の読み込み順序で依存関係ループが作成される可能性があるためです。 これにより、システムが初期化コードを実行する前に DLL が使用される可能性があります。 同様に、エントリ ポイント関数は、プロセスの終了時に FreeLibrary 関数 (または FreeLibrary を呼び出す関数) を呼び出してはなりません。これは、システムが終了コードを実行した後に DLL が使用される可能性があるためです。
エントリ ポイント関数が呼び出されたときに、Kernel32.dll がプロセス アドレス空間に読み込まれると保証されるため、Kernel32.dll で関数を呼び出しても、初期化コードが実行される前に DLL が使用されることはありません。 したがって、エントリ ポイント関数は、他の DLL を読み込まない Kernel32.dll で関数を呼び出すことができます。 たとえば、 DllMain では、重要なセクションやミューテックスなどの 同期オブジェクト を作成し、TLS を使用できます。 残念ながら、Kernel32.dllに安全な機能の包括的なリストはありません.
Kernel32.dll 以外の DLL を必要とする関数を呼び出すと、診断が困難な問題が発生する可能性があります。 たとえば、User、Shell、COM 関数を呼び出すと、一部の関数が他のシステム コンポーネントを読み込むため、アクセス違反エラーが発生する可能性があります。 逆に、終了中にこのような関数を呼び出すと、対応するコンポーネントが既にアンロードまたは初期化されていない可能性があるため、アクセス違反エラーが発生する可能性があります。
DLL 通知はシリアル化されるため、エントリ ポイント関数は他のスレッドまたはプロセスとの通信を試行しないでください。 その結果、デッドロックが発生する可能性があります。
DLL を記述するときのベスト プラクティスについては、 ダイナミック リンク ライブラリのベスト プラクティスに関するページを参照してください。
DLL が C ランタイム ライブラリ (CRT) にリンクされている場合、CRT によって提供されるエントリ ポイントは、グローバルおよび静的な C++ オブジェクトのコンストラクターとデストラクターを呼び出します。 したがって、 DllMain に対するこれらの制限は、コンストラクターとデストラクター、およびそれらから呼び出されるコードにも適用されます。
DLL が静的 C ランタイム ライブラリ (CRT) とリンクされていない限り、DLL_PROCESS_ATTACHを受信するときに DisableThreadLibraryCalls を呼び出すことをお勧めします。
必要条件
| 要件 | 価値 |
|---|---|
| サポートされる最小クライアント |
Windows XP [デスクトップ アプリのみ] |
| サポートされている最小のサーバー |
Windows Server 2003 [デスクトップ アプリのみ] |
| ヘッダー |
|