Retrieving Supported Service Methods

Service methods encapsulate functionality that each service defines and implements. They are specific to each type of service type and are represented by a unique GUID.

For example, the Contacts service defines a BeginSync method that applications call to prepare the device for synchronizing Contact objects, and an EndSync method to notify the device that synchronization has completed.

Applications can programmatically query the supported methods and access these methods and their attributes by using the IPortableDeviceServiceCapabilities interface.

Service methods should not be confused with WPD commands. WPD commands are part of the standard WPD Device Driver Interface (DDI), and are the mechanism for communication between a WPD application and the driver. Commands are predefined, grouped by categories, for example, WPD_CATEGORY_COMMON, and are represented by a PROPERTYKEY structure. For more information, see the Commands topic.

The WpdServicesApiSample application includes code that demonstrates how an application can retrieve the methods supported by a given Contacts service by using the interfaces in the following table.

Interface Description
IPortableDeviceService Used to retrieve the IPortableDeviceServiceCapabilities interface to access the supported service methods.
IPortableDeviceServiceCapabilities Provides access to the supported methods, method attributes and method parameters.
IPortableDevicePropVariantCollection Contains the list of supported methods.
IPortableDeviceValues Contains the attributes for a method and for a given method's parameters.
IPortableDeviceKeyCollection Contains the parameters for a given method.

 

When the user chooses option "5" at the command line, the application invokes the ListSupportedMethods method that is found in the ServiceMethods.cpp module.

Note that prior to retrieving the list of events, the sample application opens a Contacts service on a connected device.

In WPD, a method is described by its name, access rights, parameters, and related data. The sample application displays a user-friendly name, for example, "CustomMethod", or a GUID. The method name or GUID is followed by access data ("Read/Write"), the name of any associated format, and the parameter data. This data includes the parameter name, usage, VARTYPE, and form.

Five methods in the ServiceMethods.cpp module support the retrieval of methods (and related data) for the given Contacts service: ListSupportedMethods, DisplayMethod, DisplayMethodAccess, DisplayFormat, and DisplayMethodParameters. The ListSupportedMethods method retrieves a count of supported methods and the GUID identifier for each; it then calls the DisplayMethod method. The DisplayMethod method calls the IPortableDeviceServiceCapapbilities::GetMethodAttributes method to retrieve the given method's options, parameters, and so on. After the DisplayMethod retrieves the method data, it renders the name (or GUID), the access restrictions, the associated format (if any), and the parameter descriptions. The DisplayMethodAccess, DisplayFormat, and DisplayMethodParameters are helper functions that render their respective fields of data.

The ListSupportedMethods method invokes the IPortableDeviceService::Capabilities method to retrieve an IPortableDeviceServiceCapabilities interface. Using this interface, it retrieves the supported methods by calling the IPortableDeviceServiceCapabilities::GetSupportedMethods method. The GetSupportedMethods method retrieves the GUIDs for each method supported by the service and copies that GUID into an IPortableDevicePropVariantCollection object.

The following code uses the ListSupportedMethods method.

// 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);
        }
    }    
}

After the ListSupportedMethods method retrieves the GUID for each event supported by the given service, it invokes the DisplayMethod method to retrieve the method-specific attributes. These attributes include: the method's script-friendly name , required access restrictions, any associated format, and list of parameters.

The DisplayMethod method invokes the IPortableDeviceServiceCapabilities::GetMethodAttributes method to retrieve a collection of attributes for the given method. It then calls the IPortableDeviceValues::GetStringValue method to retrieve the method's name. The DisplayMethod calls the IPortableDeviceValues::GetUnsignedIntegerValue to retrieve the access restrctions. After this, it calls IPortableDeviceValues::GetGuidValue to retrieve any associated format. And, finally, the DisplayMethod calls the IPortableDeviceValues::GetIPortableDeviceKeyCollectionValue to retrieve the parameter data. It passes the data returned by these methods to the DisplayMethodAccess, DisplayFormat, and DisplayMethodParameters helper functions, which render the information for the given method.

The following code uses the DisplayMethod method.

// 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;

    }
}

The DisplayMethodAccess helper function receives a DWORD value that contains the method's access options. It compares this value to WPD_COMMAND_ACCESS_READ and WPD_COMMAND_ACCESS_READWRITE to determine the method's access privilege. Using the result, it renders a string indicating the access restriction for the given method.

The following code uses the DisplayMethodAccess helper function.

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;
    }
}

The DisplayMethod helper function receives an IPortableDeviceServiceCapabilities object and the method's GUID as parameters. Using the IPortableDeviceServiceCapabilities object, it invokes the IPortableDeviceServiceCapabilities::GetMethodAttributes method to retrieve the method attributes and render them in the application's console window.

The DisplayMethodParameters helper function receives an IPortableDeviceServiceCapabilities object, the method's GUID, and an IPortableDeviceKeyCollection object containing the method parameters. Using the IPortableDeviceKeyCollection object, it invokes the IPortableDeviceServiceCapabilities::GetMethodParameterAttributes method to retrieve the parameter's name, usage, VARTYPE, and form. It renders this information in the application's console window.

The following code uses the DisplayMethodParameters helper function.

// 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