Compartilhar via


Invocando métodos de serviço de forma assíncrona

O aplicativo WpdServiceApiSample inclui código que demonstra como um aplicativo pode invocar os métodos de serviço de forma assíncrona. Este exemplo usa as interfaces a seguir.

Interface Descrição
IPortableDeviceService Usado para recuperar a interface IPortableDeviceServiceMethods para invocar métodos em um determinado serviço.
IPortableDeviceServiceMethods Usado para invocar um método de serviço.
IPortableDeviceValues Usado para manter os parâmetros de método de saída e os resultados do método de entrada. Isso poderá ser NULL se o método não exigir parâmetros ou retornar resultados.
IPortableDeviceServiceMethodCallback Implementado pelo aplicativo para receber os resultados do método quando um método for concluído.

 

Quando o usuário escolhe a opção "10" na linha de comando, o aplicativo invoca o método InvokeMethodsAsync encontrado no módulo ServiceMethods.cpp. Observe que, antes de invocar os métodos, o aplicativo de exemplo abre um serviço Contatos em um dispositivo conectado.

Os métodos de serviço encapsulam a funcionalidade que cada serviço define e implementa. Eles são exclusivos para cada tipo de serviço e são representados por um GUID. Por exemplo, o serviço Contatos define um método BeginSync que os aplicativos chamam para preparar o dispositivo para sincronizar objetos Contact e um método EndSync para notificar o dispositivo de que a sincronização foi concluída. Os aplicativos executam um método de serviço de dispositivo portátil chamando IPortableDeviceServiceMethods::Invoke.

Os métodos de serviço não devem ser confundidos com comandos WPD. Os comandos WPD fazem parte da DDI (Interface de Driver de Dispositivo) WPD padrão e são o mecanismo de comunicação entre um aplicativo WPD e o driver. Os comandos são predefinidos, agrupados por categorias (por exemplo, WPD_CATEGORY_COMMON) e são representados por uma estrutura PROPERTYKEY . Um aplicativo envia comandos para o driver de dispositivo chamando IPortableDeviceService::SendCommand. Para obter mais informações, consulte o tópico Comandos.

O método InvokeMethodsAsync invoca IPortableDeviceService::Methods para recuperar uma interface IPortableDeviceServiceMethods . Usando essa interface, ela invoca a função auxiliar InvokeMethodAsync duas vezes; uma vez para o método BeginSync e uma vez para o método EndSync . Neste exemplo, , InvokeMethodAsync aguarda indefinidamente que um evento global seja sinalizado quando IPortableDeviceServiceMethodCallback::OnComplete é chamado.

O código a seguir usa o método 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);
        }
    }
}

A função auxiliar InvokeMethodAsync faz o seguinte para cada método que ele invoca:

  • Cria um identificador de evento global que ele monitora para determinar a conclusão do método.
  • Cria um objeto CMethodCallback que é fornecido como um argumento para IPortableDeviceServiceMethods:InvokeAsync.
  • Chama o método IPortableDeviceServiceMethods::InvokeAsync para invocar o método especificado.
  • Monitora o identificador de evento global para conclusão.
  • Executa a limpeza.

A classe CMethodCallback demonstra como um aplicativo pode implementar IPortableDeviceServiceMethodCallback. A implementação de OnComplete nessa classe sinaliza um evento para notificar o aplicativo de que o método de serviço foi concluído. Além do método OnComplete , essa classe implementa AddRef, QueryInterface e Release, que são usados para manter a contagem de referência do objeto e as interfaces que ele implementa.

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