Erstellen eines semisynchronen Aufrufs mit C++

Semisynchrone Aufrufe sind die empfohlene Methode zum Aufrufen von WMI-Methoden wie IWbemServices::ExecMethod und Anbietermethoden, z. B. die Chkdsk-Methode der Win32 _ LogicalDisk-Klasse.

Ein Nachteil der synchronen Verarbeitung ist, 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 an den Aufrufer steuern. Große Resultsets aus Abfragen können z. B. viel Zeit in Anspruch nehmen, um die Übermittlung zu übermitteln, und der Aufrufer muss erhebliche Systemressourcen für die Übermittlung aufwenden.

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

Im folgenden Verfahren wird beschrieben, wie ein semisynchroner Aufruf mit der IWbemServices-Schnittstelle durchgeführt wird.

So erstellen Sie einen semisynchronen Aufruf mit der IWbemServices-Schnittstelle

  1. Rufen Sie wie gewohnt auf, aber wenn das Flag WBEM _ FLAG RETURN _ _ IMMEDIATELY im IFlags-Parameter festgelegt ist.

    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 Speicherplatz und verbessert die Reaktionsfähigkeit.

  2. Suchen Sie nach Ihren Ergebnissen.

    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 abrufen. Der IEnumWbemClassObject::NextAsync-Aufruf ist nicht blockierend und gibt sofort zurück. Im Hintergrund beginnt WMI mit der Bereitstellung der angeforderten Anzahl von Objekten, indem IWbemObjectSink::Indicateaufgerufen wird. WMI beendet dann und wartet auf einen weiteren NextAsync-Aufruf.

    Wenn Sie eine Methode aufrufen, die keinen Enumerator zurückgibt, z. B. IWbemServices::GetObject,müssen Sie den ppCallResult-Parameter 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 Anruf.

    Bei einem 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 frei, indem Sie die Releasemethode IEnumWbemClassObject:: aufrufen. Der Aufruf von Release führt dazu, dass WMI die Übermittlung aller noch erhaltenen Objekte abbricht.

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

Das C++-Codebeispiel in diesem Thema erfordert, dass die folgenden # include-Anweisungen ordnungsgemäß kompiliert werden.

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

Im folgenden Codebeispiel wird gezeigt, wie ein semisynchroner Aufruf von GetObjectauftritt.

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