サービス メソッドの非同期呼び出し
WpdServiceApiSample アプリケーションには、アプリケーションがサービス メソッドを非同期的に呼び出す方法を示すコードが含まれています。 このサンプルでは、次のインターフェイスを使用します。
インターフェイス | 説明 |
---|---|
IPortableDeviceService | 特定のサービスでメソッドを呼び出すために IPortableDeviceServiceMethods インターフェイスを取得するために使用されます。 |
IPortableDeviceServiceMethods | サービス メソッドを呼び出すために使用されます。 |
IPortableDeviceValues | 送信メソッドパラメーターと受信メソッドの結果を保持するために使用されます。 メソッドがパラメーターを必要としない場合や結果を返す場合は 、NULL を 指定できます。 |
IPortableDeviceServiceMethodCallback | メソッドが完了したときにメソッドの結果を受け取るためにアプリケーションによって実装されます。 |
ユーザーがコマンド ラインでオプション "10" を選択すると、アプリケーションは ServiceMethods.cpp モジュールにある InvokeMethodsAsync メソッドを呼び出します。 メソッドを呼び出す前に、サンプル アプリケーションは接続されているデバイスで Contacts サービスを開きます。
サービス メソッドは、各サービスが定義して実装する機能をカプセル化します。 これらはサービスの種類ごとに一意であり、GUID で表されます。 たとえば、Contacts サービスは、アプリケーションが Contact オブジェクトを同期するためにデバイスを準備するために呼び出す BeginSync メソッドと、同期が完了したことをデバイスに通知する EndSync メソッドを定義します。 アプリケーションは、 IPortableDeviceServiceMethods::Invoke を呼び出してポータブル デバイス サービス メソッドを実行します。
サービス メソッドを WPD コマンドと混同しないでください。 WPD コマンドは、標準の WPD デバイス ドライバー インターフェイス (DDI) の一部であり、WPD アプリケーションとドライバー間の通信のメカニズムです。 コマンドは定義済みで、カテゴリ ( たとえば、WPD_CATEGORY_COMMON) でグループ化され、 PROPERTYKEY 構造体で表されます。 アプリケーションは 、IPortableDeviceService::SendCommand を呼び出して、デバイス ドライバーにコマンドを送信します。 詳細については、「コマンド」トピックを参照してください。
InvokeMethodsAsync メソッドは、IPortableDeviceService::Methods を呼び出して IPortableDeviceServiceMethods インターフェイスを取得します。 このインターフェイスを使用して、 InvokeMethodAsync ヘルパー関数を 2 回呼び出します。 BeginSync メソッドの場合は 1 回、 EndSync メソッドの場合は 1 回です。 この例では、 InvokeMethodAsync は 、IPortableDeviceServiceMethodCallback::OnComplete が呼び出されたときに、グローバル イベントが通知されるまで無期限に待機します。
次のコードでは 、InvokeMethodsAsync メソッドを 使用します。
// Invoke methods on the Contacts Service asynchornously.
// BeginSync and EndSync are methods defined by the FullEnumerationSync Device Service.
void InvokeMethodsAsync(IPortableDeviceService* pService)
{
HRESULT hr = S_OK;
CComPtr<IPortableDeviceServiceMethods> pMethods;
if (pService == NULL)
{
printf("! A NULL IPortableDeviceService interface pointer was received\n");
return;
}
// Get an IPortableDeviceServiceMethods interface from the IPortableDeviceService interface to
// invoke methods.
hr = pService->Methods(&pMethods);
if (FAILED(hr))
{
printf("! Failed to get IPortableDeviceServiceMethods from IPortableDeviceService, hr = 0x%lx\n",hr);
}
// Invoke the BeginSync method asynchronously
if (SUCCEEDED(hr))
{
printf("Invoking %ws asynchronously...\n",NAME_FullEnumSyncSvc_BeginSync);
// This method does not take any parameters, so we pass in NULL
hr = InvokeMethodAsync(pMethods, METHOD_FullEnumSyncSvc_BeginSync, NULL);
if (FAILED(hr))
{
printf("! Failed to invoke %ws asynchronously, hr = 0x%lx\n",NAME_FullEnumSyncSvc_BeginSync, hr);
}
}
// Invoke the EndSync method asynchronously
if (SUCCEEDED(hr))
{
printf("Invoking %ws asynchronously...\n",NAME_FullEnumSyncSvc_EndSync);
hr = InvokeMethodAsync(pMethods, METHOD_FullEnumSyncSvc_EndSync, NULL);
if (FAILED(hr))
{
printf("! Failed to invoke %ws asynchronously, hr = 0x%lx\n",NAME_FullEnumSyncSvc_EndSync, hr);
}
}
}
InvokeMethodAsync ヘルパー関数は、呼び出すメソッドごとに次の処理を行います。
- メソッドの完了を決定するために監視するグローバル イベント ハンドルを作成します。
- IPortableDeviceServiceMethods:InvokeAsync の引数として指定される CMethodCallback オブジェクトを作成します。
- IPortableDeviceServiceMethods::InvokeAsync メソッドを呼び出して、指定されたメソッドを呼び出します。
- グローバル イベント ハンドルの完了を監視します。
- クリーンアップを実行します。
CMethodCallback クラスは、アプリケーションで IPortableDeviceServiceMethodCallback を実装する方法を示しています。 このクラスの OnComplete の実装は、サービス メソッドが完了したことをアプリケーションに通知するイベントを通知します。 OnComplete メソッドに加えて、このクラスは AddRef、QueryInterface、Release を実装します。これは、オブジェクトの参照カウントと実装するインターフェイスを維持するために使用されます。
class CMethodCallback : public IPortableDeviceServiceMethodCallback
{
public:
CMethodCallback () : m_cRef(1)
{
}
~CMethodCallback ()
{
}
public:
// IPortableDeviceServiceMethodCallback::QueryInterface
virtual HRESULT STDMETHODCALLTYPE OnComplete(
HRESULT hrStatus,
IPortableDeviceValues* /*pResults*/) // We are ignoring results as our methods will not return any results
{
printf("** Method completed, status HRESULT = 0x%lx **\n", hrStatus);
if (g_hMethodCompleteEvent != NULL)
{
SetEvent(g_hMethodCompleteEvent);
}
return S_OK;
}
// IUnknown::AddRef
virtual ULONG STDMETHODCALLTYPE AddRef(void)
{
InterlockedIncrement((long*) &m_cRef);
return m_cRef;
}
// IUnknown::QueryInterface
virtual HRESULT STDMETHODCALLTYPE QueryInterface(
REFIID riid,
LPVOID* ppvObj)
{
HRESULT hr = S_OK;
if (ppvObj == NULL)
{
hr = E_INVALIDARG;
return hr;
}
if ((riid == IID_IUnknown) ||
(riid == IID_IPortableDeviceServiceMethodCallback))
{
AddRef();
*ppvObj = this;
}
else
{
*ppvObj = NULL;
hr = E_NOINTERFACE;
}
return hr;
}
// IUnknown::Release
virtual ULONG STDMETHODCALLTYPE Release(void)
{
ULONG ulRefCount = m_cRef - 1;
if (InterlockedDecrement((long*) &m_cRef) == 0)
{
delete this;
return 0;
}
return ulRefCount;
}
private:
DWORD m_cRef;
};
関連トピック