Bagikan melalui


Memanggil Metode Layanan Secara Asinkron

Aplikasi WpdServiceApiSample menyertakan kode yang menunjukkan bagaimana aplikasi dapat memanggil metode layanan secara asinkron. Sampel ini menggunakan antarmuka berikut.

Antarmuka Deskripsi
IPortableDeviceService Digunakan untuk mengambil antarmuka IPortableDeviceServiceMethods untuk memanggil metode pada layanan tertentu.
IPortableDeviceServiceMethods Digunakan untuk memanggil metode layanan.
IPortableDeviceValues Digunakan untuk menahan parameter metode keluar, dan hasil metode masuk. Ini bisa NULL jika metode tidak memerlukan parameter apa pun atau mengembalikan hasil apa pun.
IPortableDeviceServiceMethodCallback Diimplementasikan oleh aplikasi untuk menerima hasil metode ketika metode telah selesai.

 

Ketika pengguna memilih opsi "10" di baris perintah, aplikasi memanggil metode InvokeMethodsAsync yang ditemukan dalam modul ServiceMethods.cpp. Perhatikan bahwa sebelum memanggil metode, aplikasi sampel membuka layanan Kontak pada perangkat yang terhubung.

Metode layanan merangkum fungsionalitas yang ditentukan dan diterapkan oleh setiap layanan. Mereka unik untuk setiap jenis layanan dan diwakili oleh GUID. Misalnya, layanan Kontak menentukan metode BeginSync yang dipanggil aplikasi untuk menyiapkan perangkat untuk menyinkronkan objek Kontak, dan metode EndSync untuk memberi tahu perangkat bahwa sinkronisasi telah selesai. Aplikasi menjalankan metode layanan perangkat portabel dengan memanggil IPortableDeviceServiceMethods::Invoke.

Metode layanan tidak boleh dikacaukan dengan perintah WPD. Perintah WPD adalah bagian dari Antarmuka Driver Perangkat (DDI) WPD standar, dan merupakan mekanisme untuk komunikasi antara aplikasi WPD dan driver. Perintah telah ditentukan sebelumnya, dikelompokkan menurut kategori (misalnya, WPD_CATEGORY_COMMON), dan diwakili oleh struktur PROPERTYKEY . Aplikasi mengirimkan perintah ke driver perangkat dengan memanggil IPortableDeviceService::SendCommand. Untuk informasi selengkapnya, lihat topik Perintah.

Metode InvokeMethodsAsync memanggil IPortableDeviceService::Methods untuk mengambil antarmuka IPortableDeviceServiceMethods . Dengan menggunakan antarmuka ini, ia memanggil fungsi pembantu InvokeMethodAsync dua kali; sekali untuk metode BeginSync dan sekali untuk metode EndSync . Dalam contoh ini, , InvokeMethodAsync menunggu tanpa batas waktu agar peristiwa global diberi sinyal ketika IPortableDeviceServiceMethodCallback::OnComplete dipanggil.

Kode berikut menggunakan metode 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);
        }
    }
}

Fungsi pembantu InvokeMethodAsync melakukan hal berikut untuk setiap metode yang dipanggilnya:

  • Membuat penanganan peristiwa global yang dipantaunya untuk menentukan penyelesaian metode.
  • Membuat objek CMethodCallback yang disediakan sebagai argumen ke IPortableDeviceServiceMethods:InvokeAsync.
  • Memanggil metode IPortableDeviceServiceMethods::InvokeAsync untuk memanggil metode yang diberikan.
  • Memantau penanganan peristiwa global untuk penyelesaian.
  • Melakukan pembersihan.

Kelas CMethodCallback menunjukkan bagaimana aplikasi dapat mengimplementasikan IPortableDeviceServiceMethodCallback. Implementasi OnComplete di kelas ini menandakan peristiwa untuk memberi tahu aplikasi bahwa metode layanan telah selesai. Selain metode OnComplete , kelas ini mengimplementasikan AddRef, QueryInterface, dan Release, yang digunakan untuk mempertahankan jumlah referensi objek dan antarmuka yang diterapkannya.

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