次の方法で共有


IRP_MN_QUERY_REMOVE_DEVICE 要求の処理

PnP マネージャーは、デバイスがコンピューターから削除されようとしていることをドライバーに通知し、コンピューターを中断せずにデバイスを削除できるかどうかを確認するために、この IRP を送信します。 また、ユーザーがデバイスのドライバーの更新を要求すると、この IRP も送信されます。

PnP マネージャーは、システム スレッドのコンテキストで IRQL PASSIVE_LEVEL でこの IRP を送信します。

デバイスのドライバーにこの IRP を送信する前に、次の処理を行います。

  • デバイス (または関連デバイス) で通知を登録したすべてのユーザー モード アプリケーションに通知します。

    これには、デバイス、デバイスのいずれかの子孫 (子デバイス、子の子など)、またはデバイスの取り出し関係のいずれかの通知を受け取るよう登録されたアプリケーションが含まれます。 アプリケーションは、CM_Register_Notification または RegisterDeviceNotification呼び出すことによって、このような通知に登録します。

    この通知に応答して、アプリケーションはデバイスの削除を準備するか (デバイスのハンドルを閉じます)、クエリに失敗します。 これらの通知を処理する方法の詳細については、「デバイス インターフェイス到着通知とデバイス削除 の登録」を参照してください。

  • デバイス (または関連デバイス) での通知に登録されたすべてのカーネル モード ドライバーに通知します。

    これには、デバイス、デバイスのいずれかの子孫、またはデバイスの取り出し関係のいずれかで通知に登録したドライバーが含まれます。 ドライバーは、EventCategoryTargetDeviceChange のイベント カテゴリを使用して IoRegisterPlugPlayNotification を呼び出すことにより、この通知に登録します。

    この通知に応じて、ドライバーはデバイスの削除を準備するか (デバイスのハンドルを閉じます)、クエリに失敗します。

  • IRP_MN_QUERY_REMOVE_DEVICE IRP をデバイスの子孫のドライバーに送信します。 デバイス スタックがこの IRP を処理する方法の詳細については、以下を参照してください。

  • (Windows 2000 以降のシステム)ファイル システムがデバイスにマウントされている場合、PnP マネージャーは、ファイル システムとすべてのファイル システム フィルターにクエリ削除要求を送信します。 デバイスに開いているハンドルがある場合、通常、ファイル システムはクエリ削除要求に失敗します。 そうでない場合、ファイル システムは通常、将来の作成が成功しないようにボリュームをロックします。 マウントされたファイル システムがクエリ削除要求をサポートしていない場合、PnP マネージャーはデバイスのクエリ削除要求に失敗します。

上記の手順がすべて成功した場合、PnP マネージャーはデバイスのドライバーに IRP_MN_QUERY_REMOVE_DEVICE を送信します。

IRP_MN_QUERY_REMOVE_DEVICE 要求は、最初にデバイス スタックの最上位ドライバーによって処理され、次に次の下位ドライバーごとに処理されます。 ドライバーは、その DispatchPnP ルーチン内の IRP の削除を処理します。

ドライバーは、IRP_MN_QUERY_REMOVE_DEVICEに応答して、次の操作を行う必要があります。

  1. デバイスをコンピューターから安全に削除できるかどうかを判断します。

    次のいずれかに該当する場合、ドライバーは、クエリ削除 IRP を失敗する必要があります。

    • デバイスを削除すると、データが失われることがあります。

    • コンポーネントにデバイスへの開いているハンドルがある場合。 (これは Windows 98/Me のみの問題です。Windows 2000 以降のバージョンの Windows では、開いているハンドルが追跡され、IRP_MN_QUERY_REMOVE_DEVICE の完了後に開いているハンドルがある場合はクエリが失敗します)。

    • ドライバーが (IRP_MN_DEVICE_USAGE_NOTIFICATION IRP を通じて) 通知を受け取った場合、デバイスはページング、クラッシュ ダンプ、または休止状態ファイルのパスにあります。

    • デバイスに対する未処理のインターフェイス参照がドライバーにある場合。 つまり、ドライバーは、IRP_MN_QUERY_INTERFACE 要求に応答してインターフェイスを提供し、インターフェイスが逆参照されていません。

  2. デバイスを削除できない場合、クエリ削除 IRP に失敗します。

    Irp- IoStatus.Status を適切なエラー状態 (通常はSTATUS_UNSUCCESSFUL) に設定し、IO_NO_INCREMENTで IoCompleteRequest 呼び出し、ドライバーの DispatchPnP ルーチンから戻ります。 IRP を次の下位ドライバーに渡さないでください。

  3. ドライバーが以前にウェイクアップのデバイスを有効にする IRP_MN_WAIT_WAKE 要求を送信した場合は、待機ウェイク IRP をキャンセルします。

  4. デバイスの以前の PnP 状態を記録します。

    ドライバーは、ドライバーが IRP_MN_QUERY_REMOVE_DEVICE 要求を受け取ったときにデバイスが存在していた PnP 状態を記録する必要があります。これは、クエリが取り消された場合にデバイスをその状態に戻す必要があるためです (IRP_MN_CANCEL_REMOVE_DEVICE)。 以前の状態は、通常は "開始" です。これは、ドライバーが IRP_MN_START_DEVICE 要求を正常に完了したときにデバイスが入力する状態です。

    ただし、他の以前の状態も可能です。 たとえば、ユーザーがデバイス マネージャーを使用してデバイスを無効にしている可能性があります。 または、IRP_MN_QUERY_CAPABILITIES 要求に応答して、親バス ドライバー (またはバス ドライバーのフィルター ドライバー) は、デバイスのハードウェアが無効になっていることを報告している可能性があります。 いずれの場合も、無効になっているデバイスのドライバーは、IRP_MN_START_DEVICE 要求を受け取る前に IRP_MN_QUERY_REMOVE_DEVICE 要求を受け取ることができます。

  5. IRP を完了します。

    関数またはフィルター ドライバーの場合:

    • Irp->IoStatus.Status を STATUS_SUCCESS に設定します。

    • IoSkipCurrentIrpStackLocation を使用して次のスタックの場所を設定し、IoCallDriverを使用して次の下位ドライバーに IRP を渡します。

    • DispatchPnP ルーチンからの戻りステータスとして IoCallDriver からステータスを伝達します。

    • IRP を完了しないでください。

    バス ドライバーの場合:

    • Irp->IoStatus.Status を STATUS_SUCCESS に設定します。

    • IO_NO_INCREMENTを使用して IRP (IoCompleteRequest) を完了します。

    • DispatchPnP ルーチンから戻ります。

デバイス スタック内のドライバーが IRP_MN_QUERY_REMOVE_DEVICEに失敗した場合、PnP マネージャーはデバイス スタックに IRP_MN_CANCEL_REMOVE_DEVICE を送信します。 これにより、ドライバーが query-remove IRP に対し、下位のドライバーが失敗したかを検出するために、IoCompletion ルーチンを必要としないようにします。

ドライバーが IRP_MN_QUERY_REMOVE_DEVICE に成功し、デバイスが削除保留中の状態であると見なされると、ドライバーは、デバイスの後続の作成要求に失敗する必要があります。 ドライバーは、ドライバーが IRP_MN_CANCEL_REMOVE_DEVICE または IRP_MN_REMOVE_DEVICEを受け取るまで、通常どおりに他のすべての IRP を処理します。