Condividi tramite


Richiamare i metodi del servizio in modo asincrono

L'applicazione WpdServiceApiSample include codice che illustra come un'applicazione può richiamare i metodi del servizio in modo asincrono. Questo esempio usa le interfacce seguenti.

Interfaccia Descrizione
IPortableDeviceService Usato per recuperare l'interfaccia IPortableDeviceServiceMethods per richiamare i metodi in un determinato servizio.
IPortableDeviceServiceMethods Usato per richiamare un metodo di servizio.
IPortableDeviceValues Usato per contenere i parametri del metodo in uscita e i risultati del metodo in ingresso. Questo può essere NULL se il metodo non richiede parametri o restituisce risultati.
IPortableDeviceServiceMethodCallback Implementato dall'applicazione per ricevere i risultati del metodo al termine di un metodo.

 

Quando l'utente sceglie l'opzione "10" nella riga di comando, l'applicazione richiama il metodo InvokeMethodsAsync trovato nel modulo ServiceMethods.cpp. Si noti che prima di richiamare i metodi, l'applicazione di esempio apre un servizio Contatti in un dispositivo connesso.

I metodi di servizio incapsulano la funzionalità che ogni servizio definisce e implementa. Sono univoci per ogni tipo di servizio e sono rappresentati da un GUID. Ad esempio, il servizio Contatti definisce un metodo BeginSync che le applicazioni chiamano per preparare il dispositivo per la sincronizzazione degli oggetti Contact e un metodo EndSync per notificare al dispositivo che la sincronizzazione è stata completata. Le applicazioni eseguono un metodo di servizio dispositivo portatile chiamando IPortableDeviceServiceMethods::Invoke.

I metodi di servizio non devono essere confusi con i comandi WPD. I comandi WPD fanno parte dell'interfaccia DDI (WPD Device Driver Interface) standard e sono il meccanismo per la comunicazione tra un'applicazione WPD e il driver. I comandi sono predefiniti, raggruppati per categorie (ad esempio, WPD_CATEGORY_COMMON) e sono rappresentati da una struttura PROPERTYKEY . Un'applicazione invia comandi al driver di dispositivo chiamando IPortableDeviceService::SendCommand. Per altre informazioni, vedere l'argomento Comandi.

Il metodo InvokeMethodsAsync richiama IPortableDeviceService::Methods per recuperare un'interfaccia IPortableDeviceServiceMethods . Usando questa interfaccia, richiama la funzione helper InvokeMethodAsync due volte; una volta per il metodo BeginSync e una volta per il metodo EndSync . In questo esempio, InvokeMethodAsync attende in modo indefinito che un evento globale venga segnalato quando viene chiamato IPortableDeviceServiceMethodCallback::OnComplete .

Il codice seguente usa il metodo 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 funzione helper InvokeMethodAsync esegue le operazioni seguenti per ogni metodo richiamato:

  • Crea un handle di eventi globale che monitora per determinare il completamento del metodo.
  • Crea un oggetto CMethodCallback fornito come argomento per IPortableDeviceServiceMethods:InvokeAsync.
  • Chiama il metodo IPortableDeviceServiceMethods::InvokeAsync per richiamare il metodo specificato.
  • Monitora l'handle dell'evento globale per il completamento.
  • Esegue la pulizia.

La classe CMethodCallback illustra come un'applicazione può implementare IPortableDeviceServiceMethodCallback. L'implementazione di OnComplete in questa classe segnala un evento per notificare all'applicazione che il metodo del servizio è stato completato. Oltre al metodo OnComplete , questa classe implementa AddRef, QueryInterface e Release, usata per mantenere il conteggio dei riferimenti dell'oggetto e le interfacce implementate.

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