使用 C++ 進行半同步呼叫

半非同步呼叫是呼叫 WMI 方法的建議方法,例如 IWbemServices::ExecMethod 和提供者方法,例如 Win32_LogicalDisk 類別的 Chkdsk 方法

同步處理的其中一個缺點是呼叫端執行緒會遭到封鎖,直到呼叫完成為止。 封鎖可能會導致處理時間延遲。 相反地,非同步呼叫必須在腳本中實作 SWbemSink 。 在 C++ 中,非同步程式碼必須實作 IWbemObjectSink 介面、使用多個執行緒,以及控制回呼叫端的資訊流程。 例如,來自查詢的大型結果集可能需要相當長的時間才能傳遞,並強制呼叫端花費大量系統資源來處理傳遞。

半同步處理可藉由輪詢實作 IWbemCallResult 介面的特殊狀態物件,來解決執行緒封鎖和未受控制傳遞問題。 透過 IWbemCallResult,您可以改善查詢、列舉和事件通知的速度和效率。

下列程式描述如何使用 IWbemServices 介面進行半同步呼叫。

若要使用 IWbemServices 介面進行半同步呼叫

  1. 如常呼叫,但在IFlags參數中設定WBEM_FLAG_RETURN_IMMEDIATELY旗標。

    您可以將 WBEM_FLAG_RETURN_IMMEDIATELY 與其他適用于特定方法的旗標結合。 例如,針對傳回列舉值的所有呼叫,使用 WBEM_FLAG_FORWARD_ONLY 旗標。 結合設定這些旗標可節省時間和空間,並改善回應性。

  2. 輪詢結果。

    如果您呼叫傳回列舉值的方法,例如 IWbemServices::CreateClassEnumIWbemServices::ExecQuery,您可以使用 IEnumWbemClassObject::NextIEnumWbemClassObject::NextAsync 方法輪詢列舉值。 IEnumWbemClassObject::NextAsync呼叫為非封鎖,並立即傳回。 在背景中,WMI 會呼叫 IWbemObjectSink::Indicate,開始傳遞所要求的物件數目。 WMI 接著會停止並等候另一個 NextAsync 呼叫。

    如果您呼叫未傳回列舉值的方法,例如 IWbemServices::GetObject,則必須將 ppCallResult 參數設定為有效的指標。 在傳回的指標上使用 IWbemCallResult::GetCallStatus 來擷取 WBEM_S_NO_ERROR

  3. 完成您的通話。

    對於傳回列舉值的呼叫,WMI 會呼叫 IWbemObjectSink::SetStatus 來報告作業完成。 如果您不需要整個結果,請呼叫 IEnumWbemClassObject::Release 方法來釋放列舉值。 呼叫 Release 會導致 WMI 取消所有剩餘物件的傳遞。

    對於不使用列舉值的呼叫,請透過 方法的plStatus參數擷取GetCallStatus物件。

本主題中的 C++ 程式碼範例需要下列#include語句才能正確編譯。

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

下列程式碼範例示範如何對 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.            
  
}

呼叫方法