Partager via


Appel asynchrone des méthodes de service

L’application WpdServiceApiSample inclut du code qui montre comment une application peut appeler les méthodes de service de manière asynchrone. Cet exemple utilise les interfaces suivantes.

Interface Description
IPortableDeviceService Permet de récupérer l’interface IPortableDeviceServiceMethods pour appeler des méthodes sur un service donné.
IPortableDeviceServiceMethods Utilisé pour appeler une méthode de service.
IPortableDeviceValues Utilisé pour contenir les paramètres de la méthode sortante et les résultats de la méthode entrante. Cette valeur peut être NULL si la méthode ne nécessite aucun paramètre ou retourne des résultats.
IPortableDeviceServiceMethodCallback Implémenté par l’application pour recevoir les résultats de la méthode lorsqu’une méthode est terminée.

 

Lorsque l’utilisateur choisit l’option « 10 » sur la ligne de commande, l’application appelle la méthode InvokeMethodsAsync qui se trouve dans le module ServiceMethods.cpp. Notez qu’avant d’appeler les méthodes, l’exemple d’application ouvre un service Contacts sur un appareil connecté.

Les méthodes de service encapsulent des fonctionnalités que chaque service définit et implémente. Elles sont propres à chaque type de service et sont représentées par un GUID. Par exemple, le service Contacts définit une méthode BeginSync que les applications appellent pour préparer l’appareil à la synchronisation des objets Contact, et une méthode EndSync pour informer l’appareil que la synchronisation est terminée. Les applications exécutent une méthode de service d’appareil portable en appelant IPortableDeviceServiceMethods::Invoke.

Les méthodes de service ne doivent pas être confondues avec les commandes WPD. Les commandes WPD font partie de l’interface de pilote de périphérique WPD standard et constituent le mécanisme de communication entre une application WPD et le pilote. Les commandes sont prédéfinies, regroupées par catégories (par exemple, WPD_CATEGORY_COMMON) et sont représentées par une structure PROPERTYKEY . Une application envoie des commandes au pilote de périphérique en appelant IPortableDeviceService::SendCommand. Pour plus d’informations, consultez la rubrique Commandes.

La méthode InvokeMethodsAsync appelle IPortableDeviceService::Methods pour récupérer une interface IPortableDeviceServiceMethods . À l’aide de cette interface, il appelle la fonction d’assistance InvokeMethodAsync deux fois ; une fois pour la méthode BeginSync et une fois pour la méthode EndSync . Dans cet exemple, InvokeMethodAsync attend indéfiniment qu’un événement global soit signalé quand IPortableDeviceServiceMethodCallback::OnComplete est appelé.

Le code suivant utilise la méthode 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);
        }
    }
}

La fonction d’assistance InvokeMethodAsync effectue les opérations suivantes pour chaque méthode qu’elle appelle :

  • Crée un handle d’événement global qu’il surveille pour déterminer l’achèvement de la méthode.
  • Crée un objet CMethodCallback fourni en tant qu’argument à IPortableDeviceServiceMethods:InvokeAsync.
  • Appelle la méthode IPortableDeviceServiceMethods::InvokeAsync pour appeler la méthode donnée.
  • Surveille la saisie semi-automatique du handle d’événement global.
  • Effectue le nettoyage.

La classe CMethodCallback montre comment une application peut implémenter IPortableDeviceServiceMethodCallback. L’implémentation d’OnComplete dans cette classe signale un événement pour informer l’application que la méthode de service est terminée. En plus de la méthode OnComplete , cette classe implémente AddRef, QueryInterface et Release, qui sont utilisées pour gérer le nombre de références de l’objet et les interfaces qu’elle implémente.

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