Durchführen eines halbsynchronen Aufrufs mit C++

Halbsynchrone Aufrufe sind die empfohlenen Mittel zum Aufrufen von WMI-Methoden, z. B. IWbemServices::ExecMethod und Anbietermethoden, z. B. die Chkdsk-Methode der Win32_LogicalDisk-Klasse.

Ein Nachteil der synchronen Verarbeitung besteht darin, dass der Aufruferthread blockiert wird, bis der Aufruf abgeschlossen ist. Die Blockierung kann zu einer Verzögerung der Verarbeitungszeit führen. Im Gegensatz dazu muss ein asynchroner Aufruf SWbemSink im Skript implementieren. In C++ muss asynchroner Code die IWbemObjectSink-Schnittstelle implementieren, mehrere Threads verwenden und den Informationsfluss zurück zum Aufrufer steuern. Große Resultsets aus Abfragen können z. B. einen erheblichen Zeitaufwand in Anspruch nehmen und den Aufrufer zwingen, erhebliche Systemressourcen für die Verarbeitung der Übermittlung aufzugeben.

Die halbsynchrone Verarbeitung löst sowohl die Threadblockierung als auch unkontrollierte Übermittlungsprobleme, indem ein spezielles Status-Objekt abgerufen wird, das die Schnittstelle IWbemCallResult implementiert. Mit IWbemCallResult können Sie die Geschwindigkeit und Effizienz von Abfragen, Enumerationen und Ereignisbenachrichtigungen verbessern.

Im folgenden Verfahren wird beschrieben, wie Sie einen halbsynchronen Aufruf mit der Schnittstelle IWbemServices ausführen.

So führen Sie einen halbsynchronen Aufruf mit der IWbemServices-Schnittstelle aus

  1. Führen Sie Ihren Aufruf wie gewohnt aus, jedoch mit dem im Parameter IFlags festgelegten Flag WBEM_FLAG_RETURN_IMMEDIATELY.

    Sie können WBEM_FLAG_RETURN_IMMEDIATELY mit anderen Flags kombinieren, die für die jeweilige Methode gültig sind. Verwenden Sie beispielsweise das Flag WBEM_FLAG_FORWARD_ONLY für alle Aufrufe, die Enumeratoren zurückgeben. Das Festlegen dieser Flags in Kombination spart Zeit und Platz und verbessert die Reaktionsfähigkeit.

  2. Abrufen für Ihre Ergebnisse.

    Wenn Sie eine Methode aufrufen, die einen Enumerator zurückgibt, z. B. IWbemServices::CreateClassEnum oder IWbemServices::ExecQuery, können Sie die Enumeratoren mit den Methoden IEnumWbemClassObject::Next oder IEnumWbemClassObject::NextAsync abfragen. Der Aufruf IEnumWbemClassObject::NextAsync ist nicht blockierend und wird sofort zurückgegeben. Im Hintergrund beginnt WMI, die angeforderte Anzahl von Objekten zu übermitteln, indem IWbemObjectSink::Indicate aufgerufen wird. WMI beendet dann und wartet auf einen weiteren Aufruf NextAsync.

    Wenn Sie eine Methode aufrufen, die keinen Enumerator zurückgibt, z. B. IWbemServices::GetObject, müssen Sie den Parameter ppCallResult auf einen gültigen Zeiger festlegen. Verwenden Sie IWbemCallResult::GetCallStatus für den zurückgegebenen Zeiger, um WBEM_S_NO_ERROR abzurufen.

  3. Beenden Sie Ihren Aufruf.

    Für einen Aufruf, der einen Enumerator zurückgibt, ruft WMI IWbemObjectSink::SetStatus auf, um den Abschluss des Vorgangs zu melden. Wenn Sie nicht das gesamte Ergebnis benötigen, geben Sie den Enumerator durch Aufrufen der Methode IEnumWbemClassObject::Release frei. Der Aufruf von Release führt dazu, dass WMI die Übermittlung aller verbleibenden Objekte abbricht.

    Rufen Sie für einen Aufruf, der keinen Enumerator verwendet, das Objekt GetCallStatus über den Parameter plStatus Ihrer Methode ab.

Das C++-Codebeispiel in diesem Thema erfordert die folgenden #include-Anweisungen für eine ordnungsgemäße Kompilierung.

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

Im folgenden Codebeispiel wird gezeigt, wie Sie einen halbsynchronen Aufruf von GetObject ausführen.

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.            
  
}

Aufrufen einer Methode