共用方式為


傳遞 Power IRP

電源 IRP 必須從裝置堆疊向下傳遞至 PDO,以確保完全管理電源轉換。 當 IRP 向下移動裝置堆疊時,驅動程式會處理可降低裝置電源的 IRP。 驅動程式會處理在 IoCompletion 常式中套用裝置電源的 IRP,因為 IRP 會移動備份裝置堆疊。

下圖顯示驅動程式在 Windows 7 和 Windows Vista 中將電源 IRP 傳遞至裝置堆疊所需的步驟。

說明在 Windows vista 中傳遞電源 irp 的圖表。

如上圖所示,在 Windows 7 和 Windows Vista 中,驅動程式必須執行下列動作:

  1. 如果設定IoCompletion常式,則呼叫IoCopyCurrentIrpStackLocationToNext;如果未設定IoCompletion常式,則呼叫IoSkipCurrentIrpStackLocation

    這兩個常式會設定下一個較低驅動程式的 IRP 堆疊位置。 複製目前的堆疊位置可確保 IoCompletion 常式執行時,IRP 堆疊指標會設定為正確的位置。

    如果撰寫錯誤的驅動程式發生呼叫 IoSkipCurrentIrpStackLocation 的錯誤,然後設定完成常式,此驅動程式可能會覆寫驅動程式下方的驅動程式所設定的完成常式。

  2. 如果需要完整的常式,請呼叫 IoSetCompletionRoutine 來設定 IoCompletion 常式。

  3. 呼叫 IoCallDriver ,將 IRP 傳遞至堆疊中的下一個較低驅動程式。

下圖顯示驅動程式在 Windows Server 2003、Windows XP 和 Windows 2000 中將電源 IRP 傳遞至裝置堆疊所需的步驟。

關閉電源 irp (windows Server 2003、windows xp 和 windows 2000) 。

如上圖所示,驅動程式必須執行下列動作:

  1. 視驅動程式類型而定,可能會呼叫 PoStartNextPowerIrp。 如需詳細資訊,請參閱 呼叫 PoStartNextPowerIrp

  2. 如果設定IoCompletion常式,則呼叫IoCopyCurrentIrpStackLocationToNext;如果未設定IoCompletion常式,則呼叫IoSkipCurrentIrpStackLocation

    這兩個常式會設定下一個較低驅動程式的 IRP 堆疊位置。 複製目前的堆疊位置可確保 IoCompletion 常式執行時,IRP 堆疊指標會設定為正確的位置。

  3. 呼叫 IoSetCompletionRoutine 以設定 IoCompletion 常式。 在 IoCompletion 常式中,大部分驅動程式 都會呼叫 PoStartNextPowerIrp ,指出它已準備好處理下一個電源 IRP。

  4. 呼叫 PoCallDriver ,將 IRP 傳遞至堆疊中的下一個較低驅動程式。

    驅動程式必須使用PoCallDriver,而不是 IoCallDriver (作為其他 IRP) ,以確保系統能夠正確同步處理電源 IRP。 如需詳細資訊,請參閱 呼叫 IoCallDriver 與呼叫 PoCallDriver

請記住,您可以在 IRQL = DISPATCH_LEVEL呼叫 IoCompletion 常式。 因此,如果驅動程式需要在 IRQL = PASSIVE_LEVEL在較低層級驅動程式完成 IRP 之後進行其他處理,驅動程式的完成常式應該排入工作專案佇列,然後傳回STATUS_MORE_PROCESSING_REQUIRED。 背景工作執行緒必須完成 IRP。

在 Windows 98/Me 中,驅動程式必須在 IRQL = PASSIVE_LEVEL完成電源 IRP。

請勿變更 Power IRP 中的函式代碼

除了控管 IRP 處理的一般規則之外, IRP_MJ_POWER IRP 具有下列特殊需求:接收電源 IRP 的驅動程式不得變更 IRP 中任何 I/O 堆疊位置中已由電源管理員或較高層級驅動程式設定的主要和次要函式程式碼。 電源管理員依賴這些函式程式碼維持不變,直到 IRP 完成為止。 違反此規則可能會導致難以偵錯的問題。 例如,作業系統可能會停止回應,或「停止回應」。

處理 Power IRP 時不要封鎖

驅動程式在處理電源 IRP 時,不得造成長時間延遲。

關閉電源 IRP 時,驅動程式應該在 Windows 7 和 Windows Vista) 或 Windows Server 2003、Windows XP 和 Windows 2000) 中呼叫IoCall (Driver (之後,儘快從其DispatchPower常式傳回。 驅動程式在傳回之前,不得等候核心事件或延遲。 如果驅動程式在短時間內無法處理電源 IRP,它應該會傳回STATUS_PENDING,並將所有傳入的 IRP 排入佇列,直到電源 IRP 完成為止。 (請注意,此行為與允許封鎖的 PnP IRP 和 DispatchPnP 常式不同。)

如果驅動程式必須等候另一個驅動程式進一步關閉裝置堆疊的電源動作,它應該會從其 DispatchPower 常式傳回STATUS_PENDING,並為電源 IRP 設定 IoCompletion 常式。 驅動程式可以在 IoCompletion 常式中執行它所需的任何工作,然後呼叫 PoStartNextPowerIrp (Windows Server 2003、Windows XP 和 Windows 2000 僅) 和 IoCompleteRequest

例如,裝置的電源原則擁有者通常會在保留系統電源 IRP 時傳送裝置電源 IRP,以設定適用于要求之系統電源狀態的裝置電源狀態。

在此情況下,電源原則擁有者應該在系統電源 IRP 中設定 IoCompletion 常式、將系統電源 IRP 傳遞至下一個較低的驅動程式,並從其 DispatchPower 常式傳回STATUS_PENDING。

IoCompletion 常式中,它會呼叫 PoRequestPowerIrp 來傳送裝置電源 IRP,並將指標傳遞至要求中的回呼常式。 IoCompletion常式應該會傳回STATUS_MORE_PROCESSING_REQUIRED。

最後,驅動程式會從回呼常式向下傳遞系統 IRP。 驅動程式不得在 DispatchPower 常式中等候核心事件,併發出目前處理之 IRP 的 IoCompletion 常式訊號;系統死結可能發生。 如需詳細資訊,請參閱 在裝置電源原則擁有者中處理系統Set-Power IRP

在類似的情況下,當系統進入睡眠狀態時,電源原則擁有者可能需要先完成一些擱置的 I/O,才能將裝置 IRP 傳送至關閉其裝置電源。 驅動程式應該排入工作專案佇列,並從DispatchPower常式傳回STATUS_PENDING,而不是在 I/O 完成並在其 DispatchPower常式中等候時發出訊號。 在背景工作執行緒中,它會等候 I/O 完成,然後傳送裝置電源 IRP。 如需詳細資訊,請參閱 IoAllocateWorkItem