C++ を使用して半同期呼び出しを行う

IWbemServices::ExecMethod などの WMI メソッドや Win32_LogicalDisk クラスの Chkdsk メソッドなどのプロバイダー メソッドを呼び出すには、半同期呼び出しが推奨される方法です。

同期処理の欠点の 1 つは、呼び出しが完了するまで呼び出し元スレッドがブロックされることです。 ブロックされると、処理時間が遅くなる可能性があります。 これに対し、非同期呼び出しでは、スクリプトで 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::Next または IEnumWbemClassObject::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.            
  
}

メソッドの呼び出し