卸載提供者
使用提供者完成 WMI 之後,它會從記憶體卸載提供者。 WMI 卸載提供者的主要原因是節省系統資源。 因此,您必須新增程式碼,讓 WMI 以有效率的方式卸載您的提供者。 它會從快取控制項中指定的間隔到 WMI 卸載提供者的兩倍間隔。
WMI 會以下列其中一種方式卸載提供者:
- 在提供者完成提供給提供者的工作之後卸載提供者。
- 當使用者關閉系統時,快速卸載所有提供者。 請注意,當 WMI 服務從命令列關閉時,WMI 會卸載同進程提供者。
雖然第一個案例較常見,但您必須撰寫提供者以取得這兩種可能性。
本主題將討論下列各節:
卸載閒置提供者
WMI 會在卸載閒置提供者時執行下列動作:
判斷提供者是否閒置。
WMI 會使用 ClearAfter 屬性來判斷提供者在卸載該提供者之前可能保持閒置的時間長度。 如需詳細資訊,請參閱 存取提供者的閒置時間。
呼叫提供者的 Release 方法。
如果提供者是純提供者, 則 Release 會完全從使用中的記憶體中移除提供者。 不過,在 WMI 呼叫 Release之後,非Pure 提供者可能會繼續執行。
存取提供者的閒置時間
提供者保持作用中的最短時間量是由 ClearAfter 屬性所決定。 您可以在衍生自 WMI 系統類別的實例中找到ClearAfter,__CacheControl位於 \root 命名空間中。
下列清單描述衍生自 __CacheControl的類別,這些類別控制提供者卸載:
- __EventConsumerProviderCacheControl
- __EventProviderCacheControl
- __EventSinkCacheControl
- __ObjectProviderCacheControl
- __PropertyProviderCacheControl
您可以編輯特定類型提供者之快取控制項實例中的 ClearAfter 屬性,以變更 WMI 允許提供者保持非使用中的最短時間量。 例如,若要限制屬性提供者可以保持閒置的時間量,您可以編輯 \root 命名空間中__PropertyProviderCacheControl實例的ClearAfter屬性。
卸載也是 WMI 用戶端的提供者
您的提供者可能需要在完成呼叫 WMI 的提供者函式之後,保留其用戶端才能執行。 例如,推送提供者可能需要對 WMI 發出查詢。 如需詳細資訊,請參閱 判斷推送或提取狀態。 在此情況下,表示提供者之 __Win32Provider實例的Pure屬性應該設定為TRUE。 如果 Pure 屬性設定為 FALSE,當 WMI 呼叫主要介面的 Release 方法時,提供者會準備在所有未處理的介面點上呼叫 IUnknown::Release 來卸載。 如需詳細資訊,請參閱 __Win32Provider中的一節。
下列程式描述如何為提供者的主要介面實作發行方法。
卸載提供者
當 WMI 呼叫提供者主要介面的 Release 方法時,釋放針對 WMI 保留的所有介面指標。
一般而言,提供者會保存 IWbemServices 和 IWbemCoNtext 介面的指標,這些介面是在 IWbemProviderInit::Initialize中提供。
如果相關聯__Win32Provider實例中的Pure屬性設定為FALSE,提供者可以在 WMI 呼叫Release之後轉換至用戶端應用程式的角色。 不過,WMI 無法卸載以用戶端系統運作的提供者,這會增加系統額外負荷。
將 Pure設定為TRUE的提供者只存在於服務要求中。 因此,這種類型的提供者無法接受用戶端應用程式的角色,而且 WMI 可以卸載它。
在關機期間卸載提供者
在正常情況下,使用 卸載也是 WMI 用戶端的提供者 中的指導方針,可讓 WMI 正確卸載您的提供者。 不過,您可能會遇到 WMI 無法初始化一般卸載程式的情況,例如當使用者選擇關閉系統時。 除了實作良好的清除策略之外,藉由使用資料儲存體的交易模型,您可以確保提供者已正確卸載。
使用者可以隨時停止 WMI。 在這種情況下,WMI 不會卸載任何提供者,也不會在任何進程內提供者上呼叫 DllCanUnloadNow 進入點。 此外,如果進程內提供者在關機時位於方法呼叫的中間,WMI 可能會結束通話中間的執行執行緒。 在此情況下,WMI 不會呼叫通常處理清除的常式,例如物件解構函式。 WMI 最多隻會呼叫 DllMain 。
當作業系統關閉 WMI 時,系統會自動釋放配置給同進程提供者的所有記憶體。 作業系統也會關閉提供者所持有的大部分資源,例如檔案控制代碼、視窗控制碼等等。 提供者不需要採取任何特定動作,即可進行這項操作。
由於 WMI 可能會在呼叫中關閉,因此提供者不應該讓資料來源處於不一致的狀態。 讓資料處於不一致的狀態,不是唯讀提供者的問題。 不過,具有寫入功能的提供者可能會想要實作某種交易模型,以在突然終止之後允許安全復原。
雖然作業系統可能會釋放一些一般系統資源,但系統不會自動釋放所有資源。 例如,作業系統可能不會釋放通訊端或資料庫連接。 相反地,提供者可能需要手動清除這類資源。 若要避免這些問題,您可以實作提供者跨進程,也可以新增清除程式碼。
最簡單的解決方案是實作您的提供者跨進程。 WMI 關閉時不會終止進程外提供者,雖然 WMI 會在 COM 逾時後釋放提供者。 清除和終止健全性問題的提供者比效能可能超出進程更為重要。
如果您必須在提供者中放置清除程式碼,您有兩個選項。 執行這種清除的其中一個位置是 DllMain,這是作業系統卸載 DLL 時呼叫的 DLL 進入點函式。 清除程式碼可以直接新增至DllMain,以回應DLL_PROCESS_DETACH。 在 DllMain 中實作清除程式碼可能有點困難,特別是在 MFC 或 ATL 等程式設計環境中。 如需詳細資訊,請參閱 Microsoft 知識庫文章 Q148791:「如何在 MFC 一般 DLL 中提供您自己的 DllMain」 (此資源可能無法在某些語言和國家/地區中使用。)
或者,您也可以將清除程式碼放在全域類別的解構函式中。 如需詳細資訊,請參閱卸載提供者。 Windows 作業系統不會在堆積上配置全域物件。 相反地,作業系統會在 DLL 卸載期間呼叫解構函式。
以下是簡單的清除程式,可放入 WMI 的全域物件內。
class CMyCleanup
{
~CMyCleanup()
{
CloseHandle(m_hOpenFile);
CloseDatabaseConnection(g_hDatabase);
}
} g_Cleanup;
使用任一方法,在清除程式碼中可以執行許多限制。 例如,執行緒和任何未隱含連結的 DLL 都無法以任何方式存取。 此外,在任何情況下都無法進行 COM 呼叫。
相關主題