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

调用方法