Descarregar um provedor

Depois de terminar com um provedor, o WMI o descarrega da memória. O principal motivo pelo qual o WMI descarrega um provedor é para conservar recursos do sistema. Portanto, você precisa adicionar um código que permita ao WMI descarregar o provedor de maneira eficiente. Pode ser necessário desde o intervalo especificado no controle de cache até o dobro desse intervalo para que o WMI descarregue um provedor.

O WMI descarrega o provedor de uma das seguintes maneiras:

  • Descarregar um provedor após ele concluir as tarefas atribuídas a ele.
  • Descarregar rapidamente todos os provedores quando o usuário desligar o sistema. Observe que o WMI descarrega provedores no processo quando o serviço do WMI é desligado da linha de comando.

Embora o primeiro cenário seja mais comum, você precisa escrever o provedor para ambas as possibilidades.

As seguintes seções são abordadas neste tópico:

Descarregar um provedor ocioso

O WMI executa as seguintes ações quando descarrega um provedor ocioso:

  • Determina se o provedor está ocioso.

    O WMI usa a propriedade ClearAfter para determinar por quanto tempo um provedor pode permanecer ocioso antes de ser descarregado. Para saber mais, confira Acessar o tempo ocioso para um provedor.

  • Chama o método Release do provedor.

    Se o provedor era puro, Release o remove completamente da memória ativa. No entanto, um provedor não puro pode continuar sendo executado após o WMI chamar Release.

Acessar o tempo ocioso para um provedor

O período mínimo que um provedor permanece ativo é determinado pela propriedade ClearAfter. Encontre ClearAfter em instâncias de classes derivadas da classe do sistema WMI __CacheControl no namespace \root.

A seguinte lista descreve as classes derivadas de __CacheControl, que controla o descarregamento do provedor:

Você pode alterar o período mínimo que o WMI permite que um provedor permaneça inativo editando a propriedade ClearAfter na instância de controle de cache para um tipo específico de provedor. Por exemplo, para limitar o período que um provedor de propriedade pode permanecer ocioso, você editaria a propriedade ClearAfter de uma instância de __PropertyProviderCacheControl no namespace \root.

Descarregar um provedor que também é um cliente do WMI

Talvez o provedor precise permanecer como cliente do WMI depois de concluir as funções de provedor que foi chamado para executar. Por exemplo, um provedor de push pode precisar emitir consultas para o WMI. Para saber mais, confira Determinar o status de push ou pull. Nesse caso, a propriedade Pure da instância de __Win32Provider que representa o provedor deve ser definida como TRUE. Se a propriedade Pure estiver definida como FALSE, o provedor se preparará para descarregar chamando IUnknown::Release em todos os pontos da interface pendentes quando o WMI chamar o método Release da interface primária. Para saber mais, confira a seção de Comentários em _Win32Provider.

O procedimento a seguir descreve como implementar um método de liberação para a interface primária do provedor.

Para descarregar um provedor

  1. Libere todos os ponteiros de interface mantidos no WMI quando o WMI chamar o método Release da interface primária do provedor.

    Normalmente, um provedor contém ponteiros para as interfaces IWbemServices e IWbemContext fornecidas em IWbemProviderInit::Initialize.

  2. Se a propriedade Pure na instância de __Win32Provider associada estiver definida como FALSE, o provedor poderá fazer a transição para a função de aplicativo cliente após o WMI chamar Release. No entanto, o WMI não pode descarregar um provedor que está operando como sistema cliente, o que aumenta a sobrecarga do sistema.

    Um provedor com Pure definido como TRUE existe apenas para solicitações de serviço. Portanto, esse tipo de provedor não pode assumir a função de um aplicativo cliente e o WMI pode descarregá-lo.

Descarregar um provedor durante o desligamento

Em circunstâncias normais, usar as diretrizes em Descarregar um provedor que também é cliente do WMI permite que o WMI descarregue o provedor corretamente. No entanto, você pode encontrar situações em que o WMI não pode instigar os procedimentos de descarregamento normais, por exemplo, quando o usuário opta por desligar o sistema. Usando um modelo de transação de armazenamento de dados, além de implementar uma boa estratégia de limpeza, você pode garantir que o provedor seja descarregado corretamente.

O usuário pode parar o WMI a qualquer momento. Nessa situação, o WMI não descarrega provedores nem chama o ponto de entrada DllCanUnloadNow em nenhum provedor em processo. Além disso, se um provedor em processo estiver no meio de uma chamada de método no momento do desligamento, o WMI poderá encerrar o thread em execução no meio da chamada. Nessa circunstância, o WMI não chama rotinas que normalmente tratam da limpeza, como um destruidor de objetos. No máximo, o WMI chamará apenas DllMain.

Quando desliga o WMI, o sistema operacional libera automaticamente toda a memória alocada a um provedor em processo. O sistema operacional também fecha a maioria dos recursos mantidos pelo provedor, como identificadores de arquivo, identificadores de janela e assim por diante. O provedor não precisa adotar nenhuma ação específica para fazer isso.

Como o WMI pode ser desligado no meio de uma chamada, um provedor não deve deixar fontes de dados em estado inconsistente. Deixar os dados em estado inconsistente não é um problema para provedores somente leitura. No entanto, provedores com capacidade de gravação podem querer implementar algum tipo de modelo de transação para permitir a reversão segura após um encerramento abrupto.

Embora o sistema operacional possa liberar alguns recursos gerais do sistema, ele não libera todos os recursos automaticamente. Por exemplo, o sistema operacional pode não liberar um soquete ou uma conexão de banco de dados. Em vez disso, o provedor pode precisar limpar esses recursos manualmente. Para evitar esses problemas, você pode implementar o provedor fora do processo ou adicionar código de limpeza.

A solução mais simples é implementar o provedor fora do processo. Um provedor fora do processo não é encerrado quando o WMI é desligado, embora o WMI libere o provedor após um tempo limite do COM. Provedores para os quais problemas de robustez de limpeza e encerramento são mais importantes do que o desempenho podem estar fora do processo.

Se você precisar colocar código de limpeza no provedor, terá duas opções. Um local para executar esse tipo de limpeza é dllMain, a função de ponto de entrada de DLL que o sistema operacional chama ao descarregar a DLL. O código de limpeza pode ser adicionado diretamente a DllMain, executando-o em resposta a DLL_PROCESS_DETACH. A implementação do código de limpeza em DllMain pode ser um pouco difícil de organizar, especialmente em ambientes de programação como o MFC ou o ATL. Para saber mais, consulte o artigo Q148791 da Base de Dados de Conhecimento da Microsoft, "Como fornecer seu DllMain em uma DLL regular do MFC". (Esse recurso pode não estar disponível em alguns idiomas, países ou regiões.)

Como alternativa, você pode colocar o código de limpeza no destruidor de uma classe global. Para saber mais, confira Descarregar um provedor. O sistema operacional Windows não aloca objetos globais no heap. Em vez disso, ele chama os destruidores durante o descarregamento da DLL.

Veja a seguir um procedimento de limpeza simples que pode caber em um objeto global para o WMI.

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

Há muitas restrições sobre o que pode ser feito no código de limpeza com qualquer uma das abordagens. Por exemplo, nem threads nem DLLs que não estão vinculadas implicitamente podem ser acessadas de nenhuma forma. Além disso, você não pode fazer chamadas COM em nenhuma circunstância.

Definir descritores de segurança de namespace

Como proteger seu provedor

Desenvolver um provedor do WMI