共用方式為


以非同步方式叫用服務方法

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協助程式函式會針對它叫用的每個方法執行下列動作:

  • 建立全域事件控制碼,它會監視以判斷方法完成。
  • 建立 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