Выгрузка поставщика

После завершения WMI с поставщиком он выгружает поставщик из памяти. Основная причина, по которой WMI выгружает поставщик, заключается в экономии системных ресурсов. Поэтому необходимо добавить код, который позволяет WMI эффективно выгружать поставщик. Для выгрузки поставщика WMI требуется в два раза больше интервала, указанного в элементе управления кэшем.

WMI выгружает поставщик одним из следующих способов:

  • Выгрузите поставщика после того, как поставщик завершит выполнение поставленных ему задач.
  • Быстрая выгрузка всех поставщиков, когда пользователь завершает работу системы. Обратите внимание, что WMI выгружает внутрипроцессные поставщики при завершении работы службы WMI из командной строки.

Хотя первый сценарий является более распространенным, необходимо написать поставщика для обоих вариантов.

В этом разделе рассматриваются следующие разделы:

Выгрузка поставщика бездействия

WMI выполняет следующие действия при выгрузке неактивного поставщика:

  • Определяет, не простаивает ли поставщик.

    WMI использует свойство ClearAfter , чтобы определить, как долго поставщик может оставаться в режиме простоя перед выгрузкой этого поставщика. Дополнительные сведения см. в разделе Доступ к времени простоя для поставщика.

  • Вызывает метод Release поставщика.

    Если поставщик был чистым поставщиком , выпуск полностью удаляет поставщик из активной памяти. Тем не менее, некюзюрный поставщик может продолжать работать после вызова WMI Release.

Доступ к времени простоя для поставщика

Минимальное время, в течение которого поставщик остается активным, определяется свойством ClearAfter . ClearAfter можно найти в экземплярах классов, производных от системного класса WMI __CacheControl в пространстве имен \root.

В следующем списке описаны классы, производные от __CacheControl, которые управляют выгрузками поставщиков.

Вы можете изменить минимальное время, в течение которого WMI позволяет поставщику оставаться неактивным, изменив свойство ClearAfter в экземпляре элемента управления кэшем для определенного типа поставщика. Например, чтобы ограничить время, в течение которого поставщик свойств может оставаться в состоянии простоя, необходимо изменить свойство ClearAfter экземпляра __PropertyProviderCacheControl в пространстве имен \root.

Выгрузка поставщика, который также является клиентом WMI

Поставщику может потребоваться оставаться клиентом WMI после завершения функций поставщика, для выполнения которого он был вызван. Например, поставщику push-уведомлений может потребоваться отправить запросы к WMI. Дополнительные сведения см. в разделе Определение состояния отправки или вытягивания. В этом случае свойству Pure экземпляра __Win32Provider , представляющего поставщик, следует задать значение TRUE. Если для свойства Pure задано значение FALSE, поставщик готовится к выгрузке, вызывая IUnknown::Release для всех незаполненных точек интерфейса, когда WMI вызывает метод Release своего основного интерфейса. Дополнительные сведения см. в разделе Примечания в __Win32Provider.

В следующей процедуре описывается, как реализовать метод выпуска для основного интерфейса поставщика.

Выгрузка поставщика

  1. Освобождение всех указателей интерфейса, удерживаемых на WMI, когда WMI вызывает метод Release основного интерфейса поставщика.

    Как правило, поставщик содержит указатели на интерфейсы IWbemServices и IWbemContext , предоставляемые в IWbemProviderInit::Initialize.

  2. Если свойству Pure в связанном экземпляре __Win32Provider присвоено значение FALSE, поставщик может перейти на роль клиентского приложения после вызова WMI Release. Однако WMI не может выгрузить поставщика, работающего в качестве клиентской системы, что увеличивает нагрузку на систему.

    Поставщик с чистым значением 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. Дополнительные сведения см. в статье базы знаний Майкрософт Q148791 "Как предоставить собственную библиотеку DLLMain в обычной библиотеке DLL MFC". (Этот ресурс может быть недоступен для некоторых языков и стран или регионов.)

Кроме того, можно также поместить код очистки в деструктор глобального класса. Дополнительные сведения см. в разделе Выгрузка поставщика. Операционная система Windows не выделяет глобальные объекты в куче. Вместо этого операционная система вызывает деструкторы во время выгрузки библиотеки DLL.

Ниже приведена простая процедура очистки, которая может поместиться внутри глобального объекта для WMI.

class CMyCleanup
{
    ~CMyCleanup()
    {
        CloseHandle(m_hOpenFile);
        CloseDatabaseConnection(g_hDatabase);
    }
} g_Cleanup;

Существует множество ограничений в отношении того, что можно сделать в коде очистки с помощью любого из подходов. Например, ни потоки, ни библиотеки DLL, которые не связаны неявно, не могут быть доступны каким-либо образом. Кроме того, вы не можете выполнять com-вызовы ни при каких обстоятельствах.

Настройка дескрипторов безопасности в среде имен

Защита поставщика

Разработка поставщика WMI