IRP_MN_QUERY_INTERFACE

IRP_MN_QUERY_INTERFACE 要求を使用すると、ドライバーは直接呼び出しインターフェイスを他のドライバーにエクスポートすることができます。

インターフェイスをエクスポートするバス ドライバーは、その子デバイス (子 PDO) に対してこの要求を処理する必要があります。 ファンクションとフィルターは、必要に応じてこの要求を処理することができます。

このコンテキストの "インターフェイス" は、1 つの、または一連のドライバーによってエクスポートされる、1 つ以上のルーチン、および場合によってはデータで構成されます。 インターフェイスには、その内容を記述する構造体と、その型を識別する GUID があります。

たとえば、PCMCIA バス ドライバーは、PCMCIA メモリ カードの書き込み保護条件の取得などの操作のルーチンが含まれている、GUID_PCMCIA_INTERFACE_STANDARD 型のインターフェイスをエクスポートします。 このようなメモリ カードのファンクション ドライバーは、PCMCIA インターフェイス ルーチンへのポインターを取得,するために、親 PCMCIA バス ドライバーに IRP_MN_QUERY_INTERFACE 要求を送信することができます。

Note

既存のインターフェイスの新しいバージョンを導入する場合は、INTERFACE 構造体の [サイズ] フィールドまたは [バージョン] フィールドを変更するのではなく、新しい GUID を作成します。 詳細については、「ドライバー定義インターフェイスの使用」を参照してください。

このセクションでは、一般的なメカニズムとして、クエリ インターフェイス IRP について説明します。 インターフェイスを公開するドライバーは、特定のインターフェイスに関する追加情報を提供する必要があります。

0x08

主要なコード

IRP_MJ_PNP

送信時

ドライバーまたはシステム コンポーネントは、デバイス用にドライバーによってエクスポートされたインターフェースに関する情報を取得するために、この IRP を送信します。

ドライバーまたはシステム コンポーネントは、任意のスレッド コンテキストの中で、IRQL = PASSIVE_LEVEL でこの IRP を送信します。

ドライバーは、デバイスに対してドライバーの AddDevice ルーチンが呼び出された後、いつでもこの IRP を受け取ることができます。 この IRP が送信されたときに、デバイスが起動される場合と起動されない場合があります (つまり、ドライバーがデバイスの IRP_MN_START_DEVICE 要求を正常に完了したと想定することはできません)。

入力パラメーター

IO_STACK_LOCATION構造体の Parameters.QueryInterface メンバーは、それ自体が、要求されるインターフェイスを記述する構造体です。 構造体には次の情報が含まれます。

CONST GUID *InterfaceType;
USHORT Size;
USHORT Version;
PINTERFACE Interface;
PVOID InterfaceSpecificData

構造体のメンバーは次のように定義されます。

InterfaceType
要求されているインターフェイスを識別する GUID を指します。 GUID は、GUID_BUS_INTERFACE_STANDARD やカスタム インターフェイスなどのシステム定義インターフェイスに対して指定できます。 システム定義インターフェイスの GUID は Wdmguid.h に記載されています。 カスタム インターフェイスの GUID は Uuidgen を使用して生成する必要があります。

[サイズ]
要求されているインターフェイスのサイズを指定します。 この IRP を処理するドライバーは、サイズ バイトより大きい INTERFACE 構造体を返す必要があります。

Version
要求されているインターフェイスのバージョンを指定します。

ドライバーが複数のバージョンのインターフェイスをサポートしている場合、ドライバーは、要求されたバージョンを超えることなく、サポートされている最も近いバージョンを返します。 IRP を送信したコンポーネントは、返された Interface.Version フィールドを調べて、その値に基づいて行う操作を決定する必要があります。

Interface
要求されたインターフェイスを返す構造体を指します。 この構造体には、INTERFACE 構造体が最初のメンバーとして含まれている必要があります。 IRP を送信するコンポーネントは、ページングされたメモリからこの構造体を割り当てます。

インターフェイスをエクスポートするドライバーは、INTERFACE 構造体を含む新しい構造体の型と、インターフェイス内のルーチンやデータのメンバーを定義します。 (ドライバーは、前述の InterfaceType メンバーで説明されているように、インターフェイスの GUID の定義も行います。)

インターフェイスをエクスポートするドライバーは、ルーチンを呼び出すことができる IRQL など、インターフェイス内の各ルーチンの実行環境を定義します。

InterfaceSpecificData
要求されているインターフェイスに関する追加情報を指定します。

一部のインターフェイスでは、IRP を送信するコンポーネントが、このフィールドに追加情報を指定します。 通常、このフィールドは NULL であり、要求されるインターフェイスを識別するには InterfaceTypeVersion があれば十分です。

出力パラメーター

成功すると、ドライバーは Parameters.QueryInterface.Interface 構造体のメンバーを入力します。

I/O 状態ブロック

ドライバーは、Irp->IoStatus.Status を STATUS_SUCCESS に設定するか、適切なエラー状態に設定します。

成功した場合、バス ドライバーは Irp->IoStatus.Information を 0 に設定します。

ファンクションまたはフィルター ドライバーは、この IRP を処理しない場合、IoSkipCurrentIrpStackLocation を呼び出し、IRP を次のドライバーに渡します。 このようなドライバーは Irp->IoStatus.Status を変更することも、IRP を完了することもしてはなりません。

バス ドライバーが要求されたインターフェイスをエクスポートせず、そのため子 PDO に対してこの IRP を処理しない場合、バス ドライバーは Irp->IoStatus.Status をそのまま残し、IRP を完了します。

操作

ドライバーは、ドライバーがサポートするインターフェイスをパラメーターが指定している場合、この IRP を処理します。

IRP がドライバーがサポートしていないインターフェイスを要求した場合は、ドライバーは、この IRP をキューに入れる必要があります。 ドライバーは、IO_STACK_LOCATION 構造体で Parameters.QueryInterface.InterfaceType をチェックする必要があります。 インターフェイスがドライバーでサポートされていない場合、ドライバーは、ブロックせずに、デバイス スタック内の次の下位ドライバーに IRP を渡す必要があります。

各インターフェイスは InterfaceReference ルーチンと InterfaceDereference ルーチンを提供する必要があり、インターフェイスをエクスポートするドライバーは、INTERFACE 構造体にこれらのルーチンのアドレスを指定する必要があります。 ドライバーは、IRP に応答してインターフェイスを返す前に、InterfaceReference ルーチンを呼び出すことによって、インターフェイスの参照カウントをインクリメントする必要があります。 インターフェイスを要求したドライバーがそのインターフェイスの使用が終了したら、そのドライバーは、インターフェイスの InterfaceDereference ルーチンを呼び出すことによって参照カウントをデクリメントする必要があります。

IRP を送信するドライバー (ドライバー x) が後でインターフェイスを別のドライバー (ドライバー y) に渡す場合、このドライバー x はインターフェイスの参照カウントをインクリメントする必要があり、ドライバー y はそれをデクリメントする必要があります。

この IRP を処理するドライバーは、要求されたインターフェイスを取得するために別のデバイス スタックに IRP を渡すことを避ける必要があります。 そのような技法では、管理が困難なデバイス スタック間での依存関係を生み出すことになります。 たとえば、2 番目のデバイス スタックで表されるデバイスは、最初のスタックの適切なドライバーがインターフェイスを逆参照するまで削除することができません。

インターフェースには、バス固有のものとバスに依存しないものがあります。 バス固有のインターフェイスは、これらのバスのヘッダー ファイルで定義されます。 システムは、標準のバス インターフェイスをエクスポートするために、バスに依存しないインターフェイスの BUS_INTERFACE_STANDARD を定義します。

プラグ アンド プレイのマイナー IRP の処理に関する一般的な規則については、「プラグ アンド プレイ」を参照してください。

この IRP は、特に、デバイスの階層化されたカーネル モード ドライバ間でルーチン エントリ ポイントを渡すために使用されます。 この IRP によって公開されているインターフェイスを、デバイス インターフェイスと混同しないでください。 デバイス インターフェイスは、主に、ユーザー モード コンポーネントまたはその他のカーネル コンポーネントで使用されるデバイスへのパスを公開するために使用されます。 デバイス インターフェイスの詳細については、「デバイス インターフェイス クラス」を参照してください。

この IRP の送信

IRP の送信の詳細については、「IRP の処理」を参照してください。 次の手順は、特にこの IRP に適用されます。

  • ページ プールから INTERFACE 構造体を割り当てて、これをゼロに初期化します。 インターフェイス コントラクトに基づいて IRQL >= DISPATCH_LEVEL でインターフェイスが呼び出される場合、呼び出し元は、非ページ プールから割り当てられたメモリに内容をコピーすることができます。

  • IRP の次の I/O スタックの場所に値を設定します。MajorFunctionIRP_MJ_PNP に、MinorFunctionIRP_MN_QUERY_INTERFACE に設定して、Parameters.QueryInterface に適切な値を設定します。

  • IoStatus.Status を STATUS_NOT_SUPPORTED に初期化します。

  • IRP と INTERFACE 構造体が不要になったら、これらの割り当てを解除します。

  • インターフェイスの仕様で説明されているように、インターフェイス ルーチンとコンテキスト パラメーターを使用します。

  • インターフェイスが不要になったら、InterfaceDereference ルーチンを使用して参照カウントをデクリメントします。 インターフェイスを逆参照した後は、インターフェイス ルーチンを呼び出さないでください。

通常、ドライバーは、ドライバーが接続されているデバイス スタックの先頭にこの IRP を送信します。 ドライバーが別のデバイス スタックにこの IRP を送信する場合、他のデバイスが、ドライバーがサービスを提供しているデバイスの先祖でない場合は、ドライバーは、他のデバイスのターゲット デバイス通知を登録する必要があります。 このようなドライバーは、EventCategoryTargetDeviceChangeEventCategory を使用して、IoRegisterPlugPlayNotification を呼び出します。 ドライバーは GUID_TARGET_DEVICE_QUERY_REMOVE 型の通知を受け取ったときに、インターフェイスを逆参照する必要があります。 ドライバーは、後続の GUID_TARGET_DEVICE_REMOVE_CANCELLED 通知を受け取った場合、インターフェイスの再クエリを実行できます。

要件

ヘッダー

Wdm.h (Wdm.h、Ntddk.h、Ntifs.h を含む)

関連項目

BUS_INTERFACE_STANDARD

INTERFACE

IoRegisterPlugPlayNotification