Creazione di una chiamata semisynchronous con C++

Le chiamate semisynchrono sono i mezzi consigliati per chiamare metodi WMI, ad esempio IWbemServices::ExecMethod e provider, ad esempio il metodo Chkdsk della classe Win32_LogicalDisk.

Uno svantaggio dell'elaborazione sincrona è che il thread del chiamante viene bloccato fino al completamento della chiamata. Il blocco può causare un ritardo nel tempo di elaborazione. Al contrario, una chiamata asincrona deve implementare SWbemSink nello script. In C++, il codice asincrono deve implementare l'interfaccia IWbemObjectSink , usare più thread e controllare il flusso di informazioni al chiamante. I set di risultati di grandi dimensioni dalle query, ad esempio, possono richiedere molto tempo per recapitare e forza il chiamante a spendere risorse di sistema significative per gestire il recapito.

L'elaborazione semisynchrono risolve sia il blocco del thread che i problemi di recapito incontrollati eseguendo il polling di un oggetto stato speciale che implementa l'interfaccia IWbemCallResult . Tramite IWbemCallResult è possibile migliorare la velocità e l'efficienza delle query, delle enumerazioni e delle notifiche degli eventi.

La procedura seguente descrive come eseguire una chiamata semisynchrono con l'interfaccia IWbemServices .

Per eseguire una chiamata semisynchronous con l'interfaccia IWbemServices

  1. Effettuare la chiamata come normale, ma con il flag WBEM_FLAG_RETURN_IMMEDIATELY impostato nel parametro IFlags .

    È possibile combinare WBEM_FLAG_RETURN_IMMEDIATELY con altri flag validi per il metodo specifico. Ad esempio, usare il flag WBEM_FLAG_FORWARD_ONLY per tutte le chiamate che restituiscono enumeratori. L'impostazione di questi flag in combinazione consente di risparmiare tempo e spazio e migliora la velocità di risposta.

  2. Eseguire il polling dei risultati.

    Se si chiama un metodo che restituisce un enumeratore, ad esempio IWbemServices::CreateClassEnum o IWbemServices::ExecQuery, è possibile eseguire il polling degli enumeratori con i metodi IEnumWbemClassObject::Next o IEnumWbemClassObject::NextAsync. La chiamata IEnumWbemClassObject::NextAsync non blocca e restituisce immediatamente. In background, WMI inizia a recapitare il numero richiesto di oggetti chiamando IWbemObjectSink::Indicate. WMI arresta quindi e attende un'altra chiamata NextAsync .

    Se si chiama un metodo che non restituisce un enumeratore, ad esempio IWbemServices::GetObject, è necessario impostare il parametro ppCallResult su un puntatore valido. Usare IWbemCallResult::GetCallStatus nel puntatore restituito per recuperare WBEM_S_NO_ERROR.

  3. Completare la chiamata.

    Per una chiamata che restituisce un enumeratore, WMI chiama IWbemObjectSink::SetStatus per segnalare il completamento dell'operazione. Se non è necessario l'intero risultato, rilasciare l'enumeratore chiamando il metodo IEnumWbemClassObject::Release . Il rilascio chiamante comporta l'annullamento del recapito di tutti gli oggetti che rimangono.

    Per una chiamata che non usa un enumeratore, recuperare l'oggetto GetCallStatus tramite il parametro plStatus del metodo.

L'esempio di codice C++ in questo argomento richiede le istruzioni di #include seguenti per la compilazione corretta.

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

Nell'esempio di codice seguente viene illustrato come eseguire una chiamata semisynchrono a 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.            
  
}

Chiamata di un metodo