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

调用方法