エラー処理と通知
プログラムで遅延読み込みされた 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
構造体がフック関数に渡されます。 このデータは、遅延読み込みヘルパー ルーチンによって使用されるデータと同じです。 通知値は、構造体と定数の定義で定義されている値のいずれかになります。
エラー フック
エラー フックは、通知フックと同じ方法で有効になります。 フック ルーチンからは、処理を続行できるように適切な値を返す必要があります (HINSTANCE
か FARPROC
)。または、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
がスローされます。 この例外は、どの点から見ても、致命的です。
詳細については、構造体と定数の定義に関する記事を参照してください。