检索受支持的服务方法

服务方法封装每个服务定义和实现的功能。 它们特定于每种服务类型,并由唯一 GUID 表示。

例如,联系人服务定义了 一个 BeginSync 方法,应用程序调用以准备用于同步联系人对象的设备,以及用于通知设备同步已完成的 EndSync 方法。

应用程序可以使用 IPortableDeviceServiceCapabilities 接口以编程方式查询受支持的方法并访问这些方法及其属性。

不应将服务方法与 WPD 命令混淆。 WPD 命令是标准 WPD 设备驱动程序接口 (DDI) 的一部分,是 WPD 应用程序和驱动程序之间通信的机制。 命令是预定义的,按类别分组,例如WPD_CATEGORY_COMMON,并由 PROPERTYKEY 结构表示。 有关详细信息,请参阅 命令 主题。

WpdServicesApiSample 应用程序包含代码,演示如何使用下表中的接口检索给定联系人服务支持的方法。

接口 说明
IPortableDeviceService 用于检索 IPortableDeviceServiceCapabilities 接口以访问受支持的服务方法。
IPortableDeviceServiceCapabilities 提供对受支持的方法、方法属性和方法参数的访问权限。
IPortableDevicePropVariantCollection 包含受支持方法的列表。
IPortableDeviceValues 包含方法的属性和给定方法的参数。
IPortableDeviceKeyCollection 包含给定方法的参数。

 

当用户在命令行中选择选项“5”时,应用程序将调用 ServiceMethods.cpp 模块中找到的 ListSupportedMethods 方法。

请注意,在检索事件列表之前,示例应用程序会在连接的设备上打开联系人服务。

在 WPD 中,方法按名称、访问权限、参数和相关数据进行描述。 示例应用程序显示用户友好名称,例如“CustomMethod”或 GUID。 方法名称或 GUID 后跟访问数据 (“读/写”) 、任何关联格式的名称和参数数据。 此数据包括参数名称、用法、VARTYPE 和窗体。

ServiceMethods.cpp 模块中的五种方法支持检索给定联系人服务的方法 (和相关数据) : ListSupportedMethodsDisplayMethodDisplayMethodAccessDisplayFormatDisplayMethodParametersListSupportedMethods 方法检索每个方法支持的方法和 GUID 标识符的计数;然后调用 DisplayMethod 方法。 DisplayMethod 方法调用 IPortableDeviceServiceCapapbabilities::GetMethodAttributes 方法以检索给定方法的选项、参数等。 DisplayMethod 检索方法数据后,它将呈现名称 (或 GUID) 、访问限制、关联格式 ((如果有) )和参数说明。 DisplayMethodAccessDisplayFormatDisplayMethodParameters 是呈现其各自数据字段的帮助程序函数。

ListSupportedMethods 方法调用 IPortableDeviceService::Capabilities 方法来检索 IPortableDeviceServiceCapabilities 接口。 使用此接口,它通过调用 IPortableDeviceServiceCapabilities::GetSupportedMethods 方法检索受支持的方法。 GetSupportedMethods 方法检索服务支持的每个方法的 GUID,并将 GUID 复制到 IPortableDevicePropVariantCollection 对象中。

以下代码使用 ListSupportedMethods 方法。

// List all supported methods on the service
void ListSupportedMethods(IPortableDeviceService* pService)
{
    HRESULT hr              = S_OK;
    DWORD   dwNumMethods    = 0;
    CComPtr<IPortableDeviceServiceCapabilities>     pCapabilities;
    CComPtr<IPortableDevicePropVariantCollection>   pMethods;

    if (pService == NULL)
    {
        printf("! A NULL IPortableDeviceService interface pointer was received\n");
        return;
    }

    // Get an IPortableDeviceServiceCapabilities interface from the IPortableDeviceService interface to
    // access the service capabilities-specific methods.
    hr = pService->Capabilities(&pCapabilities);
    if (FAILED(hr))
    {
        printf("! Failed to get IPortableDeviceServiceCapabilities from IPortableDeviceService, hr = 0x%lx\n",hr);
    }

    // Get all methods supported by the service.
    if (SUCCEEDED(hr))
    {
        hr = pCapabilities->GetSupportedMethods(&pMethods);
        if (FAILED(hr))
        {
            printf("! Failed to get supported methods from the service, hr = 0x%lx\n",hr);
        }
    }

    // Get the number of supported methods found on the service.
    if (SUCCEEDED(hr))
    {
        hr = pMethods->GetCount(&dwNumMethods);
        if (FAILED(hr))
        {
            printf("! Failed to get number of supported methods, hr = 0x%lx\n",hr);
        }
    }

    printf("\n%d Supported Methods Found on the service\n\n", dwNumMethods);

    // Loop through each method and display it
    if (SUCCEEDED(hr))
    {
        for (DWORD dwIndex = 0; dwIndex < dwNumMethods; dwIndex++)
        {
            PROPVARIANT pv = {0};
            PropVariantInit(&pv);
            hr = pMethods->GetAt(dwIndex, &pv);

            if (SUCCEEDED(hr))
            {
                // We have a method.  It is assumed that
                // methods are returned as VT_CLSID VarTypes.
                if (pv.puuid != NULL)
                {
                    DisplayMethod(pCapabilities, *pv.puuid);
                    printf("\n");
                }
            }

            PropVariantClear(&pv);
        }
    }    
}

ListSupportedMethods 方法检索给定服务支持的每个事件的 GUID 后,它将调用 DisplayMethod 方法来检索特定于方法的属性。 这些属性包括:方法的脚本友好名称、所需的访问限制、任何关联的格式和参数列表。

DisplayMethod 方法调用 IPortableDeviceServiceCapabilities::GetMethodAttributes 方法以检索给定方法的属性集合。 然后,它调用 IPortableDeviceValues::GetStringValue 方法以检索方法的名称。 DisplayMethod 调用 IPortableDeviceValues::GetUnsignedIntegerValue 以检索访问 restrctions。 在此之后,它会调用 IPortableDeviceValues::GetGuidValue 以检索任何关联的格式。 最后, DisplayMethod 调用 IPortableDeviceValues::GetIPortableDeviceKeyCollectionValue 来检索参数数据。 它将这些方法返回的数据传递给 DisplayMethodAccessDisplayFormatDisplayMethodParameters 帮助程序函数,这些函数呈现给定方法的信息。

以下代码使用 DisplayMethod 方法。

// Display basic information about a method
void DisplayMethod(
    IPortableDeviceServiceCapabilities* pCapabilities,
    REFGUID                             Method)
{
    CComPtr<IPortableDeviceValues> pAttributes;

    // Get the method attributes which describe the method
    HRESULT hr = pCapabilities->GetMethodAttributes(Method, &pAttributes);
    if (FAILED(hr))
    {
        printf("! Failed to get the method attributes, hr = 0x%lx\n",hr);
    }

    if (SUCCEEDED(hr))
    {
        PWSTR   pszMethodName  = NULL;
        DWORD   dwMethodAccess = WPD_COMMAND_ACCESS_READ;
        GUID    guidFormat     = GUID_NULL;

        CComPtr<IPortableDeviceValues>          pOptions;
        CComPtr<IPortableDeviceKeyCollection>   pParameters;

        // Display the name of the method if available. Otherwise, fall back to displaying the GUID.
        hr = pAttributes->GetStringValue(WPD_METHOD_ATTRIBUTE_NAME, &pszMethodName);
        if (SUCCEEDED(hr))
        {
            printf("%ws", pszMethodName);
        }
        else
        {
            printf("%ws", (PWSTR)CGuidToString(Method));
        }       

        // Display the method access if available, otherwise default to WPD_COMMAND_ACCESS_READ access
        hr = pAttributes->GetUnsignedIntegerValue(WPD_METHOD_ATTRIBUTE_ACCESS, &dwMethodAccess);
        if (FAILED(hr))
        {
            dwMethodAccess = WPD_COMMAND_ACCESS_READ;
            hr = S_OK;
        }
        printf("\n\tAccess: ");
        DisplayMethodAccess(dwMethodAccess);

        // Display the associated format if specified.
        // Methods that have an associated format may only be supported for that format.
        // Methods that don't have associated formats generally apply to the entire service.
        hr = pAttributes->GetGuidValue(WPD_METHOD_ATTRIBUTE_ASSOCIATED_FORMAT, &guidFormat);
        if (SUCCEEDED(hr))
        {
            printf("\n\tAssociated Format: ");
            DisplayFormat(pCapabilities, guidFormat);
        }

        // Display the method parameters, if available
        hr = pAttributes->GetIPortableDeviceKeyCollectionValue(WPD_METHOD_ATTRIBUTE_PARAMETERS, &pParameters);
        if (SUCCEEDED(hr))
        {
            DisplayMethodParameters(pCapabilities, Method, pParameters);
        }
        
        CoTaskMemFree(pszMethodName);
        pszMethodName = NULL;

    }
}

DisplayMethodAccess 帮助程序函数接收包含该方法的访问选项的 DWORD 值。 它将此值与WPD_COMMAND_ACCESS_READ和WPD_COMMAND_ACCESS_READWRITE进行比较,以确定方法的访问特权。 使用结果,它呈现一个字符串,指示给定方法的访问限制。

以下代码使用 DisplayMethodAccess 帮助程序函数。

void DisplayMethodAccess(
    DWORD   dwAccess)
{
    switch(static_cast<WPD_COMMAND_ACCESS_TYPES>(dwAccess))
    {
        case WPD_COMMAND_ACCESS_READ:
            printf("Read");
            break;
            
        case WPD_COMMAND_ACCESS_READWRITE:
            printf("Read/Write");
            break;

        default:
            printf("Unknown Access");
            break;
    }
}

DisplayMethod 帮助程序函数接收 IPortableDeviceServiceCapabilities 对象和方法的 GUID 作为参数。 使用 IPortableDeviceServiceCapabilities 对象,它将调用 IPortableDeviceServiceCapabilities::GetMethodAttributes 方法以检索方法属性并在应用程序的控制台窗口中呈现它们。

DisplayMethodParameters 帮助程序函数接收 IPortableDeviceServiceCapabilities 对象、方法的 GUID 和包含方法参数的 IPortableDeviceKeyCollection 对象。 它使用 IPortableDeviceKeyCollection 对象调用 IPortableDeviceServiceCapabilities::GetMethodParameterAttributes 方法以检索参数的名称、用法、VARTYPE 和表单。 它在应用程序的控制台窗口中呈现此信息。

以下代码使用 DisplayMethodParameters 帮助程序函数。

// Display the method parameters.
void DisplayMethodParameters(
    IPortableDeviceServiceCapabilities* pCapabilities,
    REFGUID                             Method,
    IPortableDeviceKeyCollection*       pParameters)
{
    DWORD   dwNumParameters = 0;

    // Get the number of parameters for this event.
    HRESULT hr = pParameters->GetCount(&dwNumParameters);
    if (FAILED(hr))
    {
        printf("! Failed to get number of parameters, hr = 0x%lx\n",hr);
    }

    printf("\n\t%d Method Parameters:\n", dwNumParameters);

    // Loop through each parameter and display it
    if (SUCCEEDED(hr))
    {
        for (DWORD dwIndex = 0; dwIndex < dwNumParameters; dwIndex++)
        {
            PROPERTYKEY parameter;
            hr = pParameters->GetAt(dwIndex, &parameter);

            if (SUCCEEDED(hr))
            {
                CComPtr<IPortableDeviceValues> pAttributes;

                // Display the parameter's Name, Usage, Vartype, and Form
                hr = pCapabilities->GetMethodParameterAttributes(Method, parameter, &pAttributes);
                if (FAILED(hr))
                {
                    printf("! Failed to get the method parameter attributes, hr = 0x%lx\n",hr);
                }

                if (SUCCEEDED(hr))
                {
                    PWSTR   pszParameterName    = NULL;
                    DWORD   dwAttributeVarType  = 0;
                    DWORD   dwAttributeForm     = WPD_PARAMETER_ATTRIBUTE_FORM_UNSPECIFIED;
                    DWORD   dwAttributeUsage    = (DWORD)-1;

                    hr = pAttributes->GetStringValue(WPD_PARAMETER_ATTRIBUTE_NAME, &pszParameterName);
                    if (SUCCEEDED(hr))
                    {
                        printf("\t\tName: %ws\n", pszParameterName);
                    }
                    else
                    {
                        printf("! Failed to get the method parameter name, hr = 0x%lx\n",hr);
                    }

                    // Read the WPD_PARAMETER_ATTRIBUTE_USAGE value, if specified. 
                    hr = pAttributes->GetUnsignedIntegerValue(WPD_PARAMETER_ATTRIBUTE_USAGE, &dwAttributeUsage);
                    if (SUCCEEDED(hr))
                    {
                        printf("\t\tUsage: ");
                        DisplayParameterUsage(dwAttributeUsage);
                        printf("\n");
                    }
                    else
                    {
                        printf("! Failed to get the method parameter usage, hr = 0x%lx\n",hr);
                    }

                    hr = pAttributes->GetUnsignedIntegerValue(WPD_PARAMETER_ATTRIBUTE_VARTYPE, &dwAttributeVarType);
                    if (SUCCEEDED(hr))
                    {
                        printf("\t\tVARTYPE: ");
                        DisplayVarType(static_cast<VARTYPE>(dwAttributeVarType));
                        printf("\n");
                    }
                    else
                    {
                        printf("! Failed to get the method parameter VARTYPE, hr = 0x%lx\n",hr);
                    }

                    // Read the WPD_PARAMETER_ATTRIBUTE_FORM value.
                    hr = pAttributes->GetUnsignedIntegerValue(WPD_PARAMETER_ATTRIBUTE_FORM, &dwAttributeForm);
                    if (FAILED(hr))
                    {
                        // If the read fails, assume WPD_PARAMETER_ATTRIBUTE_FORM_UNSPECIFIED
                        dwAttributeForm = WPD_PARAMETER_ATTRIBUTE_FORM_UNSPECIFIED;
                        hr = S_OK;
                    }

                    printf("\t\tForm: ");
                    DisplayParameterForm(dwAttributeForm);
                    printf("\n");

                    CoTaskMemFree(pszParameterName);
                    pszParameterName = NULL;
                }
                
                printf("\n");
            }
        }
    }
}

IPortableDeviceKeyCollection

IPortableDeviceService

IPortableDeviceServiceCapabilities

IPortableDeviceValues

WpdServicesApiSample