Fazer uma chamada semissíncrona com C++

Chamadas semissíncronas são os meios recomendados para chamar métodos WMI, como IWbemServices::ExecMethod e métodos de provedor, como o método Chkdsk da classe Win32_LogicalDisk.

Uma desvantagem do processamento síncrono é que o thread do chamador é bloqueado até que a chamada seja concluída. O bloqueio pode causar um atraso no tempo de processamento. Por outro lado, uma chamada assíncrona deve implementar SWbemSink no script. Em C++, o código assíncrono deve implementar a interface IWbemObjectSink, usar vários threads e controlar o fluxo de informações de volta para o chamador. Grandes conjuntos de resultados de consultas, por exemplo, podem levar um tempo considerável para entregar e força o chamador a gastar recursos significativos do sistema para lidar com a entrega.

O processamento semissíncrono resolve o bloqueio de thread e os problemas de entrega não controlados sondando um objeto de status especial que implementa a interface IWbemCallResult. Por meio de IWbemCallResult, você pode melhorar a velocidade e a eficiência de consultas, enumerações e notificações de eventos.

O procedimento a seguir descreve como fazer uma chamada semissíncrona com a interface IWbemServices.

Para fazer uma chamada semissíncrona com a interface IWbemServices

  1. Faça sua chamada normalmente, mas com o sinalizador WBEM_FLAG_RETURN_IMMEDIATELY definido no parâmetro IFlags.

    Você pode combinar WBEM_FLAG_RETURN_IMMEDIATELY com outros sinalizadores válidos para o método específico. Por exemplo, use o sinalizador WBEM_FLAG_FORWARD_ONLY para todas as chamadas que retornam enumeradores. Definir esses sinalizadores em combinação economiza tempo e espaço e melhora a capacidade de resposta.

  2. Sonde seus resultados.

    Se chamar um método que retorna um enumerador, como IWbemServices::CreateClassEnum ou IWbemServices::ExecQuery, você poderá sondar os enumeradores com os métodos IEnumWbemClassObject::Next ou IEnumWbemClassObject::NextAsync. A chamada IEnumWbemClassObject::NextAsync não está sendo desbloqueada e retorna imediatamente. Em segundo plano, o WMI começa a entregar o número solicitado de objetos chamando IWbemObjectSink::Indicate. Em seguida, o WMI para e aguarda outra chamada NextAsync.

    Se você chamar um método que não retorna um enumerador, como IWbemServices::GetObject, defina o parâmetro ppCallResult como um ponteiro válido. Use IWbemCallResult::GetCallStatus no ponteiro retornado para recuperar WBEM_S_NO_ERROR.

  3. Conclua sua chamada.

    Para uma chamada que retorna um enumerador, o WMI chama IWbemObjectSink::SetStatus para relatar a conclusão da operação. Se você não precisar do resultado inteiro, libere o enumerador chamando o método IEnumWbemClassObject::Release. Chamar Release resulta no cancelamento pelo WMI da entrega de todos os objetos restantes.

    Para uma chamada que não usa um enumerador, recupere o objeto GetCallStatus por meio do parâmetro plStatus do método.

O exemplo de código C++ neste tópico requer que as instruções #include a seguir sejam compiladas corretamente.

#include <comdef.h>
#include <wbemidl.h>

O exemplo de código a seguir mostra como fazer uma chamada semissíncrona para GetObject.

void GetObjSemiSync(IWbemServices *pSvc)
{

    IWbemCallResult *pCallRes = 0;
    IWbemClassObject *pObj = 0;
    
    HRESULT hRes = pSvc->GetObject(_bstr_t(L"MyClass=\"AAA\""), 0,
        0, 0, &pCallRes
        );
        
    if (hRes || pCallRes == 0)
        return;
        
    while (true)
    {
        LONG lStatus = 0;
        HRESULT hRes = pCallRes->GetCallStatus(5000, &lStatus);
        if ( hRes == WBEM_S_NO_ERROR || hRes != WBEM_S_TIMEDOUT )
            break;

        // Do another task
    }

    hRes = pCallRes->GetResultObject(5000, &pObj);
    if (hRes)
    {
        pCallRes->Release();
        return;
    }

    pCallRes->Release();

    // Use the object.

    // ...

    // Release it.
    // ===========
        
    pObj->Release();    // Release objects not owned.            
  
}

Chamar um método