卸載提供者

使用提供者完成 WMI 之後,它會從記憶體卸載提供者。 WMI 卸載提供者的主要原因是節省系統資源。 因此,您必須新增程式碼,讓 WMI 以有效率的方式卸載您的提供者。 它會從快取控制項中指定的間隔到 WMI 卸載提供者的兩倍間隔。

WMI 會以下列其中一種方式卸載提供者:

  • 在提供者完成提供給提供者的工作之後卸載提供者。
  • 當使用者關閉系統時,快速卸載所有提供者。 請注意,當 WMI 服務從命令列關閉時,WMI 會卸載同進程提供者。

雖然第一個案例較常見,但您必須撰寫提供者以取得這兩種可能性。

本主題將討論下列各節:

卸載閒置提供者

WMI 會在卸載閒置提供者時執行下列動作:

  • 判斷提供者是否閒置。

    WMI 會使用 ClearAfter 屬性來判斷提供者在卸載該提供者之前可能保持閒置的時間長度。 如需詳細資訊,請參閱 存取提供者的閒置時間

  • 呼叫提供者的 Release 方法。

    如果提供者是純提供者, 則 Release 會完全從使用中的記憶體中移除提供者。 不過,在 WMI 呼叫 Release之後,非Pure 提供者可能會繼續執行。

存取提供者的閒置時間

提供者保持作用中的最短時間量是由 ClearAfter 屬性所決定。 您可以在衍生自 WMI 系統類別的實例中找到ClearAfter,__CacheControl位於 \root 命名空間中。

下列清單描述衍生自 __CacheControl的類別,這些類別控制提供者卸載:

您可以編輯特定類型提供者之快取控制項實例中的 ClearAfter 屬性,以變更 WMI 允許提供者保持非使用中的最短時間量。 例如,若要限制屬性提供者可以保持閒置的時間量,您可以編輯 \root 命名空間中__PropertyProviderCacheControl實例的ClearAfter屬性。

卸載也是 WMI 用戶端的提供者

您的提供者可能需要在完成呼叫 WMI 的提供者函式之後,保留其用戶端才能執行。 例如,推送提供者可能需要對 WMI 發出查詢。 如需詳細資訊,請參閱 判斷推送或提取狀態。 在此情況下,表示提供者之 __Win32Provider實例的Pure屬性應該設定為TRUE。 如果 Pure 屬性設定為 FALSE,當 WMI 呼叫主要介面的 Release 方法時,提供者會準備在所有未處理的介面點上呼叫 IUnknown::Release 來卸載。 如需詳細資訊,請參閱 __Win32Provider中的一節。

下列程式描述如何為提供者的主要介面實作發行方法。

卸載提供者

  1. 當 WMI 呼叫提供者主要介面的 Release 方法時,釋放針對 WMI 保留的所有介面指標。

    一般而言,提供者會保存 IWbemServicesIWbemCoNtext 介面的指標,這些介面是在 IWbemProviderInit::Initialize中提供。

  2. 如果相關聯__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 呼叫。

設定 Namepace 安全性描述項

保護您的提供者

開發 WMI 提供者