异步调用服务方法

WpdServiceApiSample 应用程序包含演示如何应用程序异步调用服务方法的代码。 此示例使用以下接口。

接口 说明
IPortableDeviceService 用于检索 IPortableDeviceServiceMethods 接口,以调用给定服务上的方法。
IPortableDeviceServiceMethods 用于调用服务方法。
IPortableDeviceValues 用于保存传出方法参数和传入方法结果。 如果方法不需要任何参数或返回任何结果,则此值可以为 NULL
IPortableDeviceServiceMethodCallback 由应用程序实现,以在方法完成时接收方法结果。

 

当用户在命令行中选择选项“10”时,应用程序将调用 ServiceMethods.cpp 模块中找到的 InvokeMethodsAsync 方法。 请注意,在调用方法之前,示例应用程序会在连接的设备上打开联系人服务。

服务方法封装每个服务定义和实现的功能。 它们对每种类型的服务都是唯一的,由 GUID 表示。 例如,联系人服务定义一个 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