處理 Windows 2000 和更新版本 (IRP_MN_QUERY_STOP_DEVICE 要求)
IRP_MN_QUERY_STOP_DEVICE要求會先由裝置堆疊中的頂端驅動程式處理,然後再由每個下一個較低的驅動程序處理。 驅動程式會在其 DispatchPnP 例程中處理停止 IRP。
為了回應 IRP_MN_QUERY_STOP_DEVICE,驅動程式必須執行下列動作:
判斷裝置是否可以停止,以及其硬體資源是否釋放,而不會對裝置造成負面影響。
如果下列任一項成立,驅動程式必須失敗查詢停止 IRP:
驅動程式已透過 IRP_MN_DEVICE_USAGE_NOTIFICATION) 收到 (通知,裝置位於分頁、休眠或損毀傾印檔案的路徑中。
無法釋放裝置的硬體資源。
如果下列條件成立,驅動程式可能會失敗查詢停止 IRP:
驅動程式不得卸除 I/O 要求,而且沒有佇列 IRP 的機制。
當裝置處於停止狀態時,驅動程式必須保存需要存取裝置的 IRP。 如果驅動程式未將 IRP 排入佇列,它不得允許停止裝置,因此必須失敗查詢停止 IRP。
此規則的例外狀況是允許卸除 I/O 的裝置。 這類裝置的驅動程式可以成功停止查詢並停止要求,而不需要佇列 IRP。
如果裝置無法停止,請失敗查詢停止 IRP。
將 Irp-IoStatus.Status> 設定為適當的錯誤狀態、使用 IO_NO_INCREMENT 呼叫 IoCompleteRequest,然後從驅動程式的 DispatchPnP 例程傳回。 請勿將 IRP 傳遞至下一個較低的驅動程式。
如果裝置可以停止,且驅動程式會將 IRP 排入佇列,請在裝置擴充功能中設定HOLD_NEW_REQUESTS旗標,讓後續 IRP 排入佇列 (請參閱在 裝置暫停時保留傳入 IRP) 。
或者,裝置的驅動程式可以延遲完全暫停裝置,直到驅動程式收到後續 IRP_MN_STOP_DEVICE 要求為止。 不過,這類驅動程式必須將任何要求排入佇列,以防止這些要求在到達時立即成功停止 IRP。 在重新啟動裝置之前,這類驅動程式必須將要求排入佇列,如下所示:
例如,IRP_MN_DEVICE_USAGE_NOTIFICATION要求 (,在裝置上放置分頁檔案) 。
異時傳輸的要求。
建立可防止驅動程式成功停止 IRP 的要求。
如果裝置無法進行中的 IRP 失敗,請確定任何傳遞至其他驅動程式例程和較低驅動程式的未處理要求都已完成。
驅動程式可以達成此目的的其中一種方式是使用參考計數和事件,以確保所有要求都已完成:
在 AddDevice 例程中,驅動程式會在裝置擴充功能中定義 I/O 參考計數,並將計數初始化為一個。
此外,驅動程式也會在其 AddDevice 例程中使用 KeInitializeEvent 建立事件,並使用 KeClearEvent 將事件初始化為 Not-Signaled 狀態。
每次處理 IRP 時,驅動程式都會使用 InterlockedIncrement 遞增參考計數。
每次完成要求時,驅動程式都會使用 InterlockedDecrement 遞減參考計數。
如果要求有,則驅動程式會遞減 IoCompletion 例程中的參考計數;如果驅動程式對要求沒有 IoCompletion 例程使用 IoCompletion 例程,則會在呼叫 IoCallDriver 之後立即遞減。
當驅動程式收到 IRP_MN_QUERY_STOP_DEVICE時,它會使用 InterlockedDecrement 遞減參考計數。 如果沒有未處理的要求,這會將參考計數減少為零。
當參考計數達到零時,驅動程式會使用 KeSetEvent 發出訊號來設定事件,指出查詢停止程式碼可以繼續。
除了上述程式,驅動程式可以在任何進行中的 IRP 後方串行化 IRP_MN_QUERY_STOP_DEVICE IRP。
執行將裝置置於停止擱置狀態所需的任何其他步驟。
在驅動程式成功查詢停止 IRP 之後,它必須準備好成功 IRP_MN_STOP_DEVICE。
完成 IRP。
在函式或篩選驅動程式中:
將 [Irp-IoStatus.Status>] 設定為 [STATUS_SUCCESS]。
使用 IoSkipCurrentIrpStackLocation 設定下一個堆疊位置,並使用 IoCallDriver將IRP傳遞至下一個較低的驅動程式。
將 狀態從IoCallDriver 傳播為 DispatchPnP 例程的傳回狀態。
請勿完成 IRP。
在匯流驅動程式中:
將 [Irp-IoStatus.Status>] 設定為 [STATUS_SUCCESS]。
不過,如果總線上的裝置使用硬體資源,請重新評估總線和子裝置的資源需求。 如果有任何需求已變更,請傳回STATUS_RESOURCE_REQUIREMENTS_CHANGED,而不是STATUS_SUCCESS。 此狀態表示成功,但要求 PnP 管理員在傳送停止 IRP 之前重新查詢您的資源。
使用 IO_NO_INCREMENT 完成 IRP (IoCompleteRequest) 。
從 DispatchPnP 例程傳回。
如果裝置堆疊中的任何驅動程序失敗 ,IRP_MN_QUERY_STOP_DEVICE,PnP 管理員會將 IRP_MN_CANCEL_STOP_DEVICE 傳送至裝置堆疊。 這可防止驅動程式要求查詢停止 IRP 的 IoCompletion 例程,以偵測較低驅動程式是否失敗 IRP。