IO_COMPLETION_ROUTINE コールバック関数 (wdm.h)
IoCompletion ルーチンは、I/O 操作の処理を完了します。
構文
IO_COMPLETION_ROUTINE IoCompletionRoutine;
NTSTATUS IoCompletionRoutine(
[in] PDEVICE_OBJECT DeviceObject,
[in] PIRP Irp,
[in, optional] PVOID Context
)
{...}
パラメーター
[in] DeviceObject
呼び出し元が指定した DEVICE_OBJECT 構造体へのポインター。 これは、ドライバーの AddDevice ルーチンによって以前に作成されたターゲット デバイスのデバイス オブジェクトです。
[in] Irp
I/O 操作を記述する IRP 構造体への呼び出し元から提供されるポインター。
[in, optional] Context
IoSetCompletionRoutine または IoSetCompletionRoutineEx を呼び出すときに以前に指定された、ドライバー固有のコンテキスト情報への呼び出し元指定ポインター。 IoCompletion ルーチンはDISPATCH_LEVELで呼び出すことができるため、コンテキスト情報は非ページ メモリに格納する必要があります。 詳細については、「解説」を参照してください。
戻り値
IoCompletion ルーチンが IRP に追加の処理が必要であると判断した場合は、STATUS_MORE_PROCESSING_REQUIREDを返す必要があります。 詳細については、「解説」を参照してください。 それ以外の場合は、STATUS_SUCCESSを返す必要があります。 (I/O マネージャーは、STATUS_MORE_PROCESSING_REQUIREDの有無のみを確認します。
注釈
ドライバーの IoCompletion ルーチンは、任意のスレッドまたは DPC コンテキストで実行され、DISPATCH_LEVEL以下の IRQL で実行されます。 DISPATCH_LEVELで実行するように記述されたコードも下位レベルで実行されるため、 IoCompletion ルーチンはDISPATCH_LEVELでの実行用に設計する必要があります。 ただし、これらのルーチンはDISPATCH_LEVELで実行することが保証されていないため、DISPATCH_LEVELで実際に実行を必要とするシステム ルーチンを呼び出す必要はありません。 (IRQLs の詳細については、「 ハードウェア優先度の管理」を参照してください)。
特定の IRP の IoCompletion ルーチンを登録するには、ドライバーは IoSetCompletionRoutine または IoSetCompletionRoutineEx を呼び出す必要があります。これにより、 IoCompletion ルーチンのアドレスが次の下位ドライバーの I/O スタックの場所に格納されます。 (したがって、最下位レベルのドライバーは IoCompletion ルーチンを登録できません。ドライバーは通常、IRP が受信されるたびに、ディスパッチ ルーチンの 1 つから IoSetCompletionRoutine または IoSetCompletionRoutineEx を呼び出します。 すべての PnP ドライバーを含むほとんどのドライバーは、 IoSetCompletionRoutine を使用して IoCompletion ルーチンを登録できます。 IoCompletion ルーチンが実行される前にアンロードされる可能性がある PnP 以外のドライバーでは、代わりに IoSetCompletionRoutineEx を使用する必要があります。
ドライバーが IRP を完了すると、 IoCompleteRequest が呼び出されます。これにより、上位レベルの各ドライバーの IoCompletion ルーチンが次に高いものから最高レベルに呼び出され、上位のすべての IoCompletion ルーチンが呼び出されるまで、または 1 つのルーチンがSTATUS_MORE_PROCESSING_REQUIREDを返すまで呼び出されます。
IRP を作成するときは、現在のドライバーと下位ドライバーのスタックの場所を割り当てます。 十分なスタックの場所を割り当てない場合、完了ルーチンが呼び出されたときに DeviceObject ポインターが NULL に設定される可能性があります。 DeviceObject パラメーターに依存するのではなく、Context フィールドを使用して IoCompletion に情報を渡す場合は、現在のドライバーに追加のスタックの場所を割り当てることを避けることができます。
IoCompletion ルーチンから STATUS_MORE_PROCESSING_REQUIREDが返された場合、下位ドライバーの IoCompleteRequest の呼び出しは直ちに返されます。 この場合、より高いレベルのドライバーは、IRP を完了するために IoCompleteRequest を呼び出す必要があります。
IoCompletion ルーチンの実装の詳細については、「Irp の完了」を参照してください。
例
IoCompletion コールバック ルーチンを定義するには、まず、定義するコールバック ルーチンの種類を識別する関数宣言を指定する必要があります。 Windows には、ドライバーのコールバック関数の種類のセットが用意されています。 コールバック関数の種類を使用して関数を宣言すると、ドライバー、静的ドライバー検証ツール (SDV)、およびその他の検証ツールのコード分析でエラーが検出され、Windows オペレーティング システム用のドライバーを記述するための要件になります。
たとえば、 という名前MyIoCompletion
の IoCompletion コールバック ルーチンを定義するには、次のコード例に示すように、IO_COMPLETION_ROUTINE型を使用します。
IO_COMPLETION_ROUTINE MyIoCompletion;
次に、コールバック ルーチンを次のように実装します。
_Use_decl_annotations_
NTSTATUS
MyIoCompletion(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PVOID Context
)
{
// Function body
}
IO_COMPLETION_ROUTINE関数型は Wdm.h ヘッダー ファイルで定義されます。 コード分析ツールを実行するときにエラーをより正確に識別するには、必ず注釈を _Use_decl_annotations_
関数定義に追加してください。 注釈を _Use_decl_annotations_
使用すると、ヘッダー ファイル内のIO_COMPLETION_ROUTINE関数型に適用される注釈が確実に使用されます。 関数宣言の要件の詳細については、「 WDM ドライバーの関数ロール型を使用して関数を宣言する」を参照してください。 の詳細 _Use_decl_annotations_
については、「 関数の動作に注釈を付ける」を参照してください。
要件
要件 | 値 |
---|---|
対象プラットフォーム | デスクトップ |
Header | wdm.h (Wdm.h、Ntddk.h、Ntifs.h を含む) |
IRQL | IRQL <= DISPATCH_LEVELで呼び出されます (「解説」セクションを参照)。 |