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. 작동을 중단하지 않고 디바이스를 컴퓨터에서 제거할 수 있는지 여부를 확인합니다.

    다음 중 하나라도 true인 경우 드라이버는 쿼리 제거 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 요청을 성공적으로 완료할 때 디바이스가 들어오는 상태인 "started"입니다.

    그러나 다른 이전 상태는 가능합니다. 예를 들어 사용자가 장치 관리자 통해 디바이스를 사용하지 않도록 설정했을 수 있습니다. 또는 IRP_MN_QUERY_CAPABILITIES 요청에 대한 응답으로 부모 버스 드라이버(또는 버스 드라이버의 필터 드라이버)가 디바이스의 하드웨어가 비활성화되었다고 보고했을 수 있습니다. 두 경우 모두 비활성화된 디바이스의 드라이버는 IRP_MN_START_DEVICE 요청을 받기 전에 IRP_MN_QUERY_REMOVE_DEVICE 요청을 받을 수 있습니다.

  5. IRP를 완료합니다.

    함수 또는 필터 드라이버에서:

    • Irp-IoStatus.Status>를 STATUS_SUCCESS 설정합니다.

    • IoSkipCurrentIrpStackLocation을 사용하여 다음 스택 위치를 설정하고 IRP를 IoCallDriver를 사용하여 다음 하위 드라이버에 전달합니다.

    • IoCallDriver의 상태 DispatchPnP 루틴에서 반환 상태 전파합니다.

    • IRP를 완료하지 마세요.

    버스 드라이버에서:

    • Irp-IoStatus.Status>를 STATUS_SUCCESS 설정합니다.

    • IO_NO_INCREMENT 사용하여 IRP(IoCompleteRequest)를 완료합니다.

    • DispatchPnP 루틴에서 반환합니다.

디바이스 스택의 드라이버가 IRP_MN_QUERY_REMOVE_DEVICE 실패하면 PnP 관리자는 디바이스 스택에 IRP_MN_CANCEL_REMOVE_DEVICE 보냅니다. 이렇게 하면 드라이버가 쿼리 제거 IRP에 대한 IoCompletion 루틴을 요구하여 하위 드라이버가 IRP에 실패했는지 여부를 감지할 수 없습니다.

드라이버가 IRP_MN_QUERY_REMOVE_DEVICE 성공하고 디바이스가 제거 보류 중 상태로 간주되면 드라이버는 디바이스에 대한 후속 만들기 요청에 실패해야 합니다. 드라이버는 드라이버가 IRP_MN_CANCEL_REMOVE_DEVICE 또는 IRP_MN_REMOVE_DEVICE 받을 때까지 다른 모든 IRP 를 평소와 같이 처리합니다.