使用 C++ 进行异步调用

用 C++ 编写的 WMI 应用程序可以使用 IWbemServices COM 接口的许多方法进行异步调用。 但是,调用 WMI 方法提供程序方法的推荐过程是使用半同步调用,因为半同步调用比异步调用更安全。 有关详细信息,请参阅使用 C++ 进行半同步调用设置异步调用的安全性

以下过程介绍了如何在进程中使用接收器进行异步调用。

使用 C++ 进行异步调用

  1. 实现 IWbemObjectSink 接口。

    所有进行异步调用的应用程序都必须实现 IWbemObjectSink。 临时事件使用者还实现 IWbemObjectSink 以接收事件通知。

  2. 登录到目标 WMI 命名空间。

    应用程序始终必须在初始化阶段调用 COM 函数 CoInitializeSecurity。 如果它们在进行异步调用之前未执行此操作,WMI 会在异步调用未完成的情况下释放应用程序接收器。 有关详细信息,请参阅初始化 WMI 应用程序的 COM

  3. 设置接收器的安全性。

    异步调用会产生可能必须处理的各种安全问题,例如,允许 WMI 访问应用程序。 有关详细信息,请参阅设置异步调用的安全性

  4. 进行异步调用。

    该方法会立即返回 WBEM_S_NO_ERROR 成功代码。 在等待操作完成时,应用程序可以继续执行其他任务。 WMI 通过调用应用程序的 IWbemObjectSink 实现中的方法向应用程序返回报告。

  5. 如有必要,请定期检查实现以获取更新。

    应用程序可以通过将异步调用中的 lFlags 参数设置为 WBEM_FLAG_SEND_STATUS 来接收中间状态通知。 WMI 通过将 IWbemObjectSink 的 lFlags 参数设置为 WBEM_STATUS_PROGRESS 来报告调用状态。

  6. 如有必要,可以通过调用 IWbemServices::CancelCallAsync 方法在 WMI 完成处理之前取消调用。

    CancelAsyncCall 方法通过立即释放指向 IWbemObjectSink 接口的指针来取消异步处理,并保证在 CancelAsyncCall 返回之前释放指针。

    如果使用实现 IUnsecured 接口的包装器对象来托管 IWbemObjectSink,你可能会发现一些额外的复杂情况。 由于应用程序必须将与原始异步调用中传递的同一指针传递给 CancelAsyncCall,因此应用程序必须保持在包装器对象上,直到明确不需要取消为止。 有关详细信息,请参阅设置异步调用的安全性

  7. 完成后,清理指针并关闭应用程序。

    WMI 通过 SetStatus 方法提供最终状态调用。

    注意

    发送最终状态更新后,WMI 通过为实现 IWbemObjectSink 接口的类调用 Release 方法来释放对象接收器。 在前面的示例中,这是 QuerySink::Release 方法。 如果想控制接收器对象的生命周期,可使用初始引用计数(即 1)来实现接收器。

     

    如果客户端应用程序在两个不同的重叠异步调用中传递相同的接收器接口,WMI 无法保证回调顺序。 进行重叠异步调用的客户端应用程序应传递不同的接收器对象,或将这些调用序列化。

以下示例需要以下引用和#include 语句。

#include <iostream>
using namespace std;
#pragma comment(lib, "wbemuuid.lib")
#include <wbemidl.h>

以下示例描述了如何使用 ExecQueryAsync 方法进行异步查询,但不创建安全设置或释放 IWbemObjectSink 对象。 有关详细信息,请参阅设置异步调用的安全性

// Set input parameters to ExecQueryAsync.
BSTR QueryLang = SysAllocString(L"WQL");
BSTR Query = SysAllocString(L"SELECT * FROM MyClass");

// Create IWbemObjectSink object and set pointer.
QuerySink *pSink = new QuerySink;

IWbemServices* pSvc = 0;

// Call ExecQueryAsync.
HRESULT hRes = pSvc->ExecQueryAsync(QueryLang, 
                                    Query, 
                                    0, 
                                    NULL, 
                                    pSink);

// Check for errors.
if (hRes)
{
    printf("ExecQueryAsync failed with = 0x%X\n", hRes);
    SysFreeString(QueryLang);
    SysFreeString(Query);
    delete pSink;    
    return ERROR;
}

注意

尚未定义 QuerySink 类,因此无法在不出错的情况下编译上述代码。 有关 QuerySink 的详细信息,请参阅 IWbemObjectSink

 

调用方法