Share via


Aufrufen von Dienstmethoden asynchron

Die WpdServiceApiSample-Anwendung enthält Code, der veranschaulicht, wie eine Anwendung die Dienstmethoden asynchron aufrufen kann. In diesem Beispiel werden die folgenden Schnittstellen verwendet.

Schnittstelle Beschreibung
IPortableDeviceService Wird verwendet, um die IPortableDeviceServiceMethods-Schnittstelle abzurufen, um Methoden für einen bestimmten Dienst aufzurufen.
IPortableDeviceServiceMethods Wird zum Aufrufen einer Dienstmethode verwendet.
IPortableDeviceValues Wird verwendet, um die ausgehenden Methodenparameter und die ergebnisse der eingehenden Methode zu speichern. Dies kann NULL sein, wenn die Methode keine Parameter erfordert oder Ergebnisse zurückgibt.
IPortableDeviceServiceMethodCallback Wird von der Anwendung implementiert, um die Methodenergebnisse zu erhalten, wenn eine Methode abgeschlossen wurde.

 

Wenn der Benutzer die Option "10" an der Befehlszeile wählt, ruft die Anwendung die InvokeMethodsAsync-Methode auf, die im Modul ServiceMethods.cpp gefunden wird. Beachten Sie, dass die Beispielanwendung vor dem Aufrufen der Methoden einen Contacts-Dienst auf einem verbundenen Gerät öffnet.

Dienstmethoden kapseln Funktionen, die jeder Dienst definiert und implementiert. Sie sind für jeden Diensttyp eindeutig und werden durch eine GUID dargestellt. Der Contacts-Dienst definiert beispielsweise eine BeginSync-Methode , die Von Anwendungen aufgerufen wird, um das Gerät für die Synchronisierung von Contact-Objekten vorzubereiten, und eine EndSync-Methode , um das Gerät darüber zu informieren, dass die Synchronisierung abgeschlossen wurde. Anwendungen führen eine portable Gerätedienstmethode durch Aufrufen von IPortableDeviceServiceMethods::Invoke aus.

Dienstmethoden sollten nicht mit WPD-Befehlen verwechselt werden. WPD-Befehle sind Teil der STANDARD WPD Device Driver Interface (DDI) und der Mechanismus für die Kommunikation zwischen einer WPD-Anwendung und dem Treiber. Befehle sind vordefinierte, nach Kategorien gruppiert (z. B. WPD_CATEGORY_COMMON) und werden durch eine PROPERTYKEY-Struktur dargestellt. Eine Anwendung sendet Befehle an den Gerätetreiber, indem IPortableDeviceService::SendCommand aufgerufen wird. Weitere Informationen finden Sie im Thema Befehle.

Die InvokeMethodsAsync-Methode ruft IPortableDeviceService::Methods auf, um eine IPortableDeviceServiceMethods-Schnittstelle abzurufen. Mit dieser Schnittstelle wird zweimal die Hilfsfunktion InvokeMethodAsync aufgerufen. einmal für die BeginSync-Methode und einmal für die EndSync-Methode . In diesem Beispiel wartet InvokeMethodAsync unbegrenzt, bis ein globales Ereignis signalisiert wird, wenn IPortableDeviceServiceMethodCallback::OnComplete aufgerufen wird.

Im folgenden Code wird die InvokeMethodsAsync-Methode verwendet.

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

Die InvokeMethodAsync-Hilfsfunktion führt für jede methode, die sie aufruft, Folgendes aus:

  • Erstellt ein globales Ereignishandle, das überwacht wird, um die Vervollständigung der Methode zu bestimmen.
  • Erstellt ein CMethodCallback-Objekt , das als Argument für IPortableDeviceServiceMethods:InvokeAsync bereitgestellt wird.
  • Ruft die IPortableDeviceServiceMethods::InvokeAsync-Methode auf, um die angegebene Methode aufzurufen.
  • Überwacht das globale Ereignishandle auf Abschluss.
  • Führt eine Bereinigung durch.

Die CMethodCallback-Klasse veranschaulicht, wie eine Anwendung IPortableDeviceServiceMethodCallback implementieren kann. Die Implementierung von OnComplete in dieser Klasse signalisiert ein Ereignis, um die Anwendung zu benachrichtigen, dass die Dienstmethode abgeschlossen wurde. Zusätzlich zur OnComplete-Methode implementiert diese Klasse AddRef, QueryInterface und Release, die verwendet werden, um die Verweisanzahl des Objekts und die von ihr implementierten Schnittstellen beizubehalten.

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