處理 IRP_MN_QUERY_REMOVE_DEVICE 請求
PnP 管理員會傳送此 IRP,通知驅動程式裝置即將從電腦中移除,並詢問裝置是否可以在不中斷電腦運作的情況下移除。 當使用者要求更新裝置的驅動程式時,也會傳送此 IRP。
PnP 管理員會在系統執行緒環境中,在 IRQL PASSIVE_LEVEL 傳送此 IRP。
它會先執行下列動作,再將此 IRP 傳送至裝置的驅動程式:
通知所有已註冊在裝置(或相關裝置)上接收通知的使用者模式應用程式。
這包括在裝置上註冊通知的應用程式、裝置的後代設備(子裝置、及子裝置的子裝置等等),或裝置的某一個 移除關係。 應用程式會藉由呼叫 CM_Register_Notification 或 RegisterDeviceNotification來註冊這類通知。
為了回應此通知,應用程式會準備移除裝置(關閉裝置的控制代碼),或拒絕查詢。 如需如何處理這些通知的詳細資訊,請參閱 註冊裝置介面抵達和裝置移除通知。
通知所有已在裝置(或相關裝置)上註冊通知的核心模式驅動程式。
這包括在裝置上註冊通知的驅動程式、裝置的其中一個子系,或裝置的其中一個 移除關係。 驅動程式會透過呼叫 IoRegisterPlugPlayNotification,並指定事件類別為 EventCategoryTargetDeviceChange,來註冊此通知。
為了回應此通知,驅動程式處理程序會準備移除裝置(關閉對裝置的控制),或操作不成功。
將 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,驅動程式必須執行下列動作:
判斷是否可以安全地從電腦移除裝置。
如果下列任一項成立,驅動程式必須拒絕查詢移除 IRP:
如果移除裝置可能會導致數據遺失。
如果元件具有裝置的開啟句柄。 (這是 Windows 98/Me 的特有問題。Windows 2000 和更新版本的 Windows 會追蹤已開啟的控制代碼,如果在 IRP_MN_QUERY_REMOVE_DEVICE 完成之後仍有開啟的控制代碼,查詢將會失敗。)
如果驅動程式已收到通知(透過 IRP_MN_DEVICE_USAGE_NOTIFICATION IRP),表示該裝置位於分頁、崩潰傾印或休眠檔案的路徑上。
如果驅動程式對裝置有未消除的介面參考。 也就是說,驅動程式提供了一個介面來回應 IRP_MN_QUERY_INTERFACE 要求,而且該介面尚未被解除參照。
如果無法移除裝置,將查詢移除 IRP 設為失敗。
將 Irp->IoStatus.Status 設定為適當的錯誤狀態(通常是STATUS_UNSUCCESSFUL)、使用 IO_NO_INCREMENT 呼叫 IoCompleteRequest,然後從驅動程式的 DispatchPnP 例程傳回。 請勿將 IRP 傳遞至下一個較低的驅動程式。
如果驅動程式先前已傳送 IRP_MN_WAIT_WAKE 要求以啟用裝置的喚醒功能,請取消該等候喚醒 IRP。
記錄裝置先前的 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 要求。
完成 IRP:
在函式或篩選驅動程式中:
將 Irp->IoStatus.Status 設定為 STATUS_SUCCESS。
使用 IoSkipCurrentIrpStackLocation 設定下一個堆疊位置,並使用 IoCallDriver將 IRP 傳遞至下一個較低驅動程式。
從 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 傳送至裝置堆疊。 這可防止驅動程式需要一個 IoCompletion 例程來偵測查詢移除 IRP,以判斷較低層驅動程式是否導致 IRP 失敗。
一旦驅動程式成功處理 IRP_MN_QUERY_REMOVE_DEVICE 並認為該裝置處於移除擱置狀態,驅動程式必須拒絕任何後續的裝置建立請求。 驅動程式會像往常一樣處理所有其他 IRP,直到驅動程式收到 IRP_MN_CANCEL_REMOVE_DEVICE 或 IRP_MN_REMOVE_DEVICE為止。