次の方法で共有


エラー処理と通知

プログラムで遅延読み込みされた DLL を使用する場合は、エラーを確実に処理する必要があります。プログラムの実行中に発生したエラーによって、ハンドルされない例外が発生するためです。 エラー処理は、フックによる回復と、例外によるレポートという 2 つの部分で構成されます。

DLL 遅延読み込みのエラー処理と通知について詳しくは、ヘルパー関数の概要に関する記事を参照してください。

フック関数の詳細については、構造体と定数の定義に関する記事を参照してください。

フックによる回復

コードでは、エラーの発生時に回復するか、別のライブラリまたはルーチンを提供することが必要になる場合があります。 ヘルパー関数にフックを指定して、代替コードを提供したり、状況を修正したりできます。 フック ルーチンからは適切な値を返して、処理を続行できるようにする必要があります (HINSTANCE または FARPROC)。 または、0 を返して、例外をスローする必要があることを示すこともできます。 また、独自の例外をスローしたり、フックから longjmp したりすることもできます。 通知フックとエラー フックがあります。 両方で同じルーチンを使用できます。

通知フック

遅延読み込み通知フックは、ヘルパー ルーチンで次のアクションが実行される直前に呼び出されます。

  • 既に読み込まれているかどうかを確認するために、ライブラリへの格納済みハンドルがチェックされる。

  • LoadLibrary を呼び出して、DLL の読み込みを試みる。

  • GetProcAddress を呼び出して、プロシージャのアドレスの取得を試みる。

  • 遅延インポート読み込みサンクに戻る。

通知フックは次の方法で有効になります。

  • 通知を受け取る独自の関数を参照するように初期化されるポインター __pfnDliNotifyHook2 の新しい定義を指定する。

    または

  • プログラムが遅延読み込みを行う DLL の呼び出しの前に、フック関数へのポインター __pfnDliNotifyHook2 を設定する。

通知が dliStartProcessing の場合、フック関数は次を返すことができます。

  • NULL

    既定のヘルパーによって DLL の読み込みが処理されます。 情報提供のみを目的として呼び出す場合に便利です。

  • 関数ポインター

    既定の遅延読み込み処理をバイパスします。 これによって独自の読み込みハンドラーを指定できます。

通知が dliNotePreLoadLibrary の場合、フック関数は次を返すことができます。

  • 0 (情報の通知のみを必要とする場合)。

  • 読み込まれた DLL の HMODULE (DLL 自体が読み込まれた場合)。

通知が dliNotePreGetProcAddress の場合、フック関数は次を返すことができます。

  • 0 (情報の通知のみを必要とする場合)。

  • インポートされた関数のアドレス (フック関数がアドレス自体を取得する場合)。

通知が dliNoteEndProcessing の場合、フック関数の戻り値は無視されます。

このポインターが初期化されている場合 (0 以外)、遅延読み込みヘルパーは、その実行中、特定の通知ポイントで関数を呼び出します。 関数ポインターには次の定義があります。

// The "notify hook" gets called for every call to the
// delay load helper.  This allows a user to hook every call and
// skip the delay load helper entirely.
//
// dliNotify == {
//  dliStartProcessing |
//  dliNotePreLoadLibrary  |
//  dliNotePreGetProc |
//  dliNoteEndProcessing}
//  on this call.
//
ExternC
PfnDliHook   __pfnDliNotifyHook2;

// This is the failure hook, dliNotify = {dliFailLoadLib|dliFailGetProc}
ExternC
PfnDliHook   __pfnDliFailureHook2;

通知では、通知値と共に、DelayLoadInfo 構造体がフック関数に渡されます。 このデータは、遅延読み込みヘルパー ルーチンによって使用されるデータと同じです。 通知値は、構造体と定数の定義で定義されている値のいずれかになります。

エラー フック

エラー フックは、通知フックと同じ方法で有効になります。 フック ルーチンからは、処理を続行できるように適切な値を返す必要があります (HINSTANCEFARPROC)。または、0 を返して、例外をスローする必要があることを示します。

ユーザー定義関数を参照するポインター変数は次のとおりです。

// This is the failure hook, dliNotify = {dliFailLoadLib|dliFailGetProc}
ExternC
PfnDliHook   __pfnDliFailureHook2;

DelayLoadInfo 構造体には、エラーの詳細なレポートに必要なすべての関連データが含まれます (GetLastError からの値を含む)。

通知が dliFailLoadLib の場合、フック関数は次を返すことができます。

  • 0 (エラーを処理できない場合)。

  • HMODULE (エラー フックによって問題が修正され、ライブラリ自体が読み込まれた場合)。

通知が dliFailGetProc の場合、フック関数は次を返すことができます。

  • 0 (エラーを処理できない場合)。

  • 有効な proc アドレス (インポート関数のアドレス) (エラー フックがアドレス自体を取得するのに成功した場合)。

例外を使用したレポート

エラー処理に必要な操作がプロシージャの中止だけである場合は、ユーザー コードによって例外を処理できる限り、フックは必要ありません。

遅延読み込みの例外コード

遅延読み込み中にエラーが発生した場合に、構造化例外コードを発生させることができます。 例外値は、VcppException マクロを使って指定します。

//
// Exception information
//
#define FACILITY_VISUALCPP  ((LONG)0x6d)
#define VcppException(sev,err)  ((sev) | (FACILITY_VISUALCPP<<16) | err)

LoadLibrary エラーの場合、標準の VcppException(ERROR_SEVERITY_ERROR, ERROR_MOD_NOT_FOUND) がスローされます。 GetProcAddress エラーの場合、スローされるエラーは VcppException(ERROR_SEVERITY_ERROR, ERROR_PROC_NOT_FOUND) です。 例外は、DelayLoadInfo 構造体へのポインターを渡します。 これは、GetExceptionInformation によって EXCEPTION_RECORD 構造体から取得される LPDWORD 値の、ExceptionInformation[0] フィールドにあります。

grAttrs フィールドに正しくないビットが設定されている場合は、例外 ERROR_INVALID_PARAMETER がスローされます。 この例外は、どの点から見ても、致命的です。

詳細については、構造体と定数の定義に関する記事を参照してください。

関連項目

遅延読み込み DLL のリンカーサポート