다음을 통해 공유


서비스 메서드를 비동기적으로 호출

WpdServiceApiSample 애플리케이션에는 애플리케이션이 서비스 메서드를 비동기적으로 호출하는 방법을 보여 주는 코드가 포함되어 있습니다. 이 샘플에서는 다음 인터페이스를 사용합니다.

인터페이스 묘사
IPortableDeviceService 지정된 서비스에서 메서드를 호출하는 IPortableDeviceServiceMethods 인터페이스를 검색하는 데 사용됩니다.
IPortableDeviceServiceMethods 서비스 메서드를 호출하는 데 사용됩니다.
IPortableDeviceValues 나가는 메서드 매개 변수와 들어오는 메서드 결과를 유지하는 데 사용됩니다. 메서드에 매개 변수가 필요하지 않거나 결과를 반환하지 않는 경우 NULL 수 있습니다.
IPortableDeviceServiceMethodCallback 메서드가 완료될 때 메서드 결과를 수신하기 위해 애플리케이션에서 구현합니다.

 

사용자가 명령줄에서 "10" 옵션을 선택하면 애플리케이션은 ServiceMethods.cpp 모듈에 있는 InvokeMethodsAsync 메서드를 호출합니다. 메서드를 호출하기 전에 샘플 애플리케이션은 연결된 디바이스에서 연락처 서비스를 엽니다.

서비스 메서드는 각 서비스가 정의하고 구현하는 기능을 캡슐화합니다. 각 서비스 유형에 고유하며 GUID로 표시됩니다. 예를 들어 Contacts 서비스는 애플리케이션이 Contact 개체 동기화를 위해 디바이스를 준비하기 위해 호출하는 BeginSync 메서드와 동기화가 완료되었음을 디바이스에 알리는 EndSync 메서드를 정의합니다. 애플리케이션은 IPortableDeviceServiceMethods::Invoke호출하여 이식 가능한 디바이스 서비스 메서드를 실행합니다.

서비스 메서드는 WPD 명령과 혼동해서는 안 됩니다. WPD 명령은 표준 WPD DDI(디바이스 드라이버 인터페이스)의 일부이며 WPD 애플리케이션과 드라이버 간의 통신 메커니즘입니다. 명령은 미리 정의되고 범주(예: WPD_CATEGORY_COMMON)로 그룹화되며 PROPERTYKEY 구조체로 표시됩니다. 애플리케이션은 IPortableDeviceService::SendCommand호출하여 디바이스 드라이버에 명령을 보냅니다. 자세한 내용은 명령 항목을 참조하세요.

InvokeMethodsAsync 메서드는 IPortableDeviceService::Methods 호출하여 IPortableDeviceServiceMethods 인터페이스를 검색합니다. 이 인터페이스를 사용하여 InvokeMethodAsync 도우미 함수를 두 번 호출합니다. BeginSync 메서드에 대해 한 번, EndSync 메서드에 대해 한 번 이 예제에서 InvokeMethodAsyncIPortableDeviceServiceMethodCallback::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 도우미 함수는 호출하는 각 메서드에 대해 다음을 수행합니다.

  • 메서드 완료 여부를 확인하기 위해 모니터링하는 전역 이벤트 핸들을 만듭니다.
  • CMethodCallback 개체를 생성하여 IPortableDeviceServiceMethods:InvokeAsync의 인수로 제공합니다.
  • IPortableDeviceServiceMethods::InvokeAsync 메서드를 호출하여 지정된 메서드를 호출합니다.
  • 전역 이벤트 핸들의 완료 상태를 모니터링합니다.
  • 정리를 수행합니다.

CMethodCallback 클래스는 애플리케이션이 IPortableDeviceServiceMethodCallback구현하는 방법을 보여 줍니다. 이 클래스에서 OnComplete 구현하면 서비스 메서드가 완료되었음을 애플리케이션에 알리는 이벤트를 알립니다. 이 클래스는 OnComplete 메서드 외에도 개체의 참조 수와 구현하는 인터페이스를 유지하는 데 사용되는 AddRef, QueryInterfaceRelease구현합니다.

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;
};

IPortableDeviceService

IPortableDeviceServiceMethodCallback

IPortableDeviceServiceMethods

WpdServicesApiSample