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