共用方式為


以異步方式叫用服務方法

WpdServiceApiSample 應用程式包含程式代碼,示範應用程式如何以異步方式叫用服務方法。 此範例會使用下列介面。

介面 描述
IPortableDeviceService 用來擷取 IPortableDeviceServiceMethods 介面,以在指定的服務上叫用方法。
IPortableDeviceServiceMethods 用於調用服務方法。
IPortableDeviceValues 用來保存傳出方法參數和傳入方法結果。 如果方法不需要任何參數或傳回任何結果,則可以 NULL
IPortableDeviceServiceMethodCallback 由應用程式實作,以在方法完成時接收方法結果。

 

當使用者在命令行選擇 「10」 選項時,應用程式會叫用 ServiceMethods.cpp 模組中找到的 InvokeMethodsAsync 方法。 請注意,在叫用 方法之前,範例應用程式會在連線的裝置上開啟聯繫人服務。

服務方法會封裝每個服務所定義和實作的功能。 它們對每種服務類型而言都是唯一的,並以 GUID 表示。 例如,Contacts 服務會定義 BeginSync 方法,應用程式呼叫以準備裝置以同步處理 Contact 物件,以及 EndSync 方法,以通知裝置同步處理已完成。 應用程式會呼叫 IPortableDeviceServiceMethods::Invoke來執行可攜式裝置服務方法。

服務方法不應與 WPD 命令混淆。 WPD 命令是標準 WPD 設備驅動器介面 (DDI) 的一部分,也是 WPD 應用程式和驅動程式之間通訊的機制。 預先定義的命令會依類別分組(例如,WPD_CATEGORY_COMMON),並以 PROPERTYKEY 結構表示。 應用程式會呼叫 IPortableDeviceService::SendCommand,將命令傳送至設備驅動器。 如需詳細資訊,請參閱命令主題。

InvokeMethodsAsync 方法會叫用 IPortableDeviceService::Methods 來擷取 IPortableDeviceServiceMethods 介面。 使用此介面,它會叫用 InvokeMethodAsync 協助程式函式兩次;一次用於 BeginSync 方法,一次用於 EndSync 方法。 在此範例中,呼叫 IPortableDeviceServiceMethodCallback::OnComplete時,InvokeMethodAsync 會無限期等候全域事件發出訊號。

下列程式代碼使用 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);
        }
    }
}

InvokeMethodAsync Helper 函式會針對它叫用的每個方法執行下列動作:

  • 建立一個全域事件句柄,讓它監視以判斷方法是否完成。
  • 建立 CMethodCallback 物件,該物件會作為自變數提供給 IPortableDeviceServiceMethods:InvokeAsync
  • 呼叫 IPortableDeviceServiceMethods::InvokeAsync 方法來叫用指定的方法。
  • 監視全域事件處理以監控其完成。
  • 進行清理。

CMethodCallback 類別示範應用程式如何實作 IPortableDeviceServiceMethodCallback。 此類別中的 OnComplete 實作會發出事件,以通知應用程式服務方法已完成。 除了 OnComplete 方法之外,這個類別也會實作 AddRefQueryInterfaceRelease,用來維護對象的參考計數和其實作的介面。

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