次の方法で共有


IRP_MN_QUERY_REMOVE_DEVICE 要求の処理

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

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

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

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

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

    この通知に応答して、アプリケーションはデバイスの取り出しを準備するか (デバイスのハンドルを閉じます)、クエリに失敗します。

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

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

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

  • IRP_MN_QUERY_REMOVE_DEVICE 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 をデバイス スタックに送信します。 これにより、下位のドライバーが IRP に失敗したかどうかを検出するために、ドライバーが、クエリ削除 IRP の IoCompletion ルーチンを必要とすることがなくなります。

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