IRP_MN_QUERY_STOP_DEVICE 요청 처리(Windows 2000 이상)
IRP_MN_QUERY_STOP_DEVICE 요청은 먼저 디바이스 스택의 상위 드라이버에 의해 처리된 다음 각 하위 드라이버에 의해 처리됩니다. 드라이버는 DispatchPnP 루틴에서 중지 IRP를 처리합니다.
IRP_MN_QUERY_STOP_DEVICE 대한 응답으로 드라이버는 다음을 수행해야 합니다.
디바이스를 중지할 수 있는지 여부와 해당 하드웨어 리소스가 부정적인 영향을 주지 않고 해제되었는지 확인합니다.
다음 중 하나라도 true인 경우 드라이버는 쿼리 중지 IRP에 실패해야 합니다.
드라이버에 디바이스가 페이징, 최대 절전 모드 또는 크래시 덤프 파일의 경로에 있음을 (IRP_MN_DEVICE_USAGE_NOTIFICATION 통해) 알림을 받았습니다.
디바이스의 하드웨어 리소스를 해제할 수 없습니다.
다음이 true인 경우 드라이버가 쿼리 중지 IRP에 실패할 수 있습니다.
드라이버는 I/O 요청을 삭제해서는 안 되며 IRP를 큐에 대기시키는 메커니즘이 없습니다.
디바이스가 중지된 상태인 동안 드라이버는 디바이스에 액세스해야 하는 IRP를 보유해야 합니다. 드라이버가 IRP를 큐에 대기하지 않는 경우 디바이스를 중지하도록 허용하면 안 되므로 쿼리 중지 IRP에 실패해야 합니다.
이 규칙의 예외는 I/O를 삭제할 수 있는 디바이스입니다. 이러한 디바이스에 대한 드라이버는 IRP를 큐에 대기하지 않고 쿼리 중지 및 중지 요청에 성공할 수 있습니다.
디바이스를 중지할 수 없는 경우 쿼리 중지 IRP에 실패합니다.
Irp-IoStatus.Status>를 적절한 오류 상태 설정하고, IO_NO_INCREMENT 사용하여 IoCompleteRequest를 호출하고, 드라이버의 DispatchPnP 루틴에서 반환합니다. IRP를 다음 하위 드라이버에 전달하지 마세요.
디바이스를 중지할 수 있고 드라이버가 IRP를 큐에 대기하는 경우 후속 IRP가 큐에 대기되도록 디바이스 확장에서 HOLD_NEW_REQUESTS 플래그를 설정합니다( 디바이스가 일시 중지될 때 들어오는 IRP 유지 참조).
또는 디바이스용 드라이버는 드라이버가 후속 IRP_MN_STOP_DEVICE 요청을 받을 때까지 디바이스 일시 중지를 완전히 연기할 수 있습니다. 그러나 이러한 드라이버는 도착 시 중지 IRP를 즉시 성공하지 못하게 하는 모든 요청을 큐에 대기해야 합니다. 디바이스가 다시 시작될 때까지 이러한 드라이버는 다음과 같은 요청을 큐에 대기해야 합니다.
IRP_MN_DEVICE_USAGE_NOTIFICATION 요청(예: 디바이스에 페이징 파일 배치).
등시 전송에 대한 요청입니다.
드라이버가 중지 IRP에 성공하지 못하도록 하는 요청을 만듭니다.
디바이스에 진행 중인 IRP가 실패할 수 없는 경우 다른 드라이버 루틴 및 낮은 드라이버에 전달된 미해결 요청이 완료되었는지 확인합니다.
드라이버에서 이 작업을 수행할 수 있는 한 가지 방법은 참조 수와 이벤트를 사용하여 모든 요청이 완료되었는지 확인하는 것입니다.
AddDevice 루틴에서 드라이버는 디바이스 확장에서 I/O 참조 수를 정의하고 개수를 1로 초기화합니다.
또한 AddDevice 루틴에서 드라이버는 KeInitializeEvent 를 사용하여 이벤트를 만들고 KeClearEvent를 사용하여 이벤트를 Not-Signaled 상태로 초기화합니다.
IRP를 처리할 때마다 드라이버는 InterlockedIncrement를 사용하여 참조 수를 증분합니다.
요청을 완료할 때마다 드라이버는 InterlockedDecrement를 사용하여 참조 수를 감소합니다.
드라이버가 요청에 IoCompletion 루틴을 사용하지 않는 경우 IoCallDriver 호출 직후 또는 요청이 있는 경우 IoCompletion 루틴의 참조 수를 감소합니다.
드라이버가 IRP_MN_QUERY_STOP_DEVICE 받으면 InterlockedDecrement를 사용하여 참조 수가 감소합니다. 미해결 요청이 없으면 참조 수가 0으로 줄어듭니다.
참조 수가 0에 도달하면 드라이버는 쿼리 중지 코드를 계속할 수 있음을 알리는 KeSetEvent 를 사용하여 이벤트를 설정합니다.
위의 프로시저 대신 드라이버는 진행 중인 모든 IRP 뒤에 IRP_MN_QUERY_STOP_DEVICE IRP를 직렬화할 수 있습니다.
디바이스를 중지 보류 상태로 두는 데 필요한 다른 단계를 수행합니다.
드라이버가 쿼리 중지 IRP에 성공하면 IRP_MN_STOP_DEVICE 성공할 준비가 되어 있어야 합니다.
IRP를 완료합니다.
함수 또는 필터 드라이버에서:
Irp-IoStatus.Status>를 STATUS_SUCCESS 설정합니다.
IoSkipCurrentIrpStackLocation을 사용하여 다음 스택 위치를 설정하고 IRP를 IoCallDriver를 사용하여 다음 하위 드라이버에 전달합니다.
IoCallDriver에서 상태 DispatchPnP 루틴에서 반환 상태 전파합니다.
IRP를 완료하지 마세요.
버스 드라이버에서:
Irp-IoStatus.Status>를 STATUS_SUCCESS 설정합니다.
그러나 버스의 디바이스가 하드웨어 리소스를 사용하는 경우 버스 및 자식 디바이스의 리소스 요구 사항을 다시 평가합니다. 요구 사항이 변경된 경우 STATUS_SUCCESS 대신 STATUS_RESOURCE_REQUIREMENTS_CHANGED 반환합니다. 이 상태 성공을 나타내지만 PnP 관리자가 중지 IRP를 보내기 전에 리소스를 다시 쿼리할 것을 요청합니다.
IO_NO_INCREMENT 사용하여 IRP(IoCompleteRequest)를 완료합니다.
DispatchPnP 루틴에서 반환합니다.
디바이스 스택의 드라이버가 IRP_MN_QUERY_STOP_DEVICE 실패하면 PnP 관리자는 디바이스 스택에 IRP_MN_CANCEL_STOP_DEVICE 보냅니다. 이렇게 하면 드라이버가 쿼리 중지 IRP에 대한 IoCompletion 루틴을 요구하여 하위 드라이버가 IRP에 실패했는지 여부를 감지할 수 없습니다.