打开服务

应用程序必须先打开服务,然后才能对服务执行操作(例如枚举内容或检索支持的事件或方法的说明)。 在 WpdServicesApiSample 应用程序中,此任务使用下表中所述的接口在 ServiceEnumeration.cpp 模块中演示。

接口 说明
IPortableDeviceServiceManager 用于枚举设备上的服务。
IPortableDeviceService 用于打开与设备服务的连接。
IPortableDeviceValues 用于保存应用程序的客户端信息。

 

打开服务的方法为 IPortableDeviceService::Open。 此方法采用两个参数:即插即用 (PnP) 标识符的服务,以及包含应用程序的客户端信息的 IPortableDeviceValues 对象。

若要获取给定服务的 PnP 标识符,应用程序会调用 IPortableDeviceServiceManager::GetDeviceServices 方法。 此方法检索服务类别 GUID (例如服务联系人) 的服务的 PnP 标识符数组。

示例服务应用程序在 ServiceEnumeration.cpp 模块的 EnumerateContactsServices 方法中检索联系人服务的 PnP 标识符。 以下代码示例取自此方法。

// For each device found, find the contacts service
for (dwIndex = 0; dwIndex < cPnpDeviceIDs; dwIndex++)
{
    DWORD   cPnpServiceIDs = 0;
    PWSTR   pPnpServiceID  = NULL;

    // First, pass NULL as the PWSTR array pointer to get the total number
    // of contacts services (SERVICE_Contacts) found on the device.
    // To find the total number of all services on the device, use GUID_DEVINTERFACE_WPD_SERVICE.
    hr = pServiceManager->GetDeviceServices(pPnpDeviceIDs[dwIndex], SERVICE_Contacts, NULL, &cPnpServiceIDs);
    
    if (SUCCEEDED(hr) && (cPnpServiceIDs > 0))
    {                               
        // For simplicity, we are only using the first contacts service on each device
        cPnpServiceIDs = 1;
        hr = pServiceManager->GetDeviceServices(pPnpDeviceIDs[dwIndex], SERVICE_Contacts, &pPnpServiceID, &cPnpServiceIDs);

        if (SUCCEEDED(hr))
        {
            // We've found the service, display it and save its PnP Identifier
            ContactsServicePnpIDs.Add(pPnpServiceID);

            printf("[%d] ", static_cast<DWORD>(ContactsServicePnpIDs.GetCount()-1));

            // Display information about the device that contains this service.
            DisplayDeviceInformation(pServiceManager, pPnpServiceID);

            // ContactsServicePnpIDs now owns the memory for this string
            pPnpServiceID = NULL;
        }
        else
        {
            printf("! Failed to get the first contacts service from '%ws, hr = 0x%lx\n",pPnpDeviceIDs[dwIndex],hr);
        }
    }
}

应用程序检索服务的 PnP 标识符后,可以设置客户端信息并调用 IPortableDeviceService::Open

在示例应用程序中,此方法在 ServiceEnumeration.cpp 模块的 ChooseDeviceService 中调用。

IPortableDeviceService 支持 CoCreateInstance 的两个 CLSID。 CLSID_PortableDeviceService 返回不聚合自由线程封送处理程序的 IPortableDeviceService 指针; CLSID_PortableDeviceServiceFTM 是一个新的 CLSID,它返回聚合自由线程封送处理程序的 IPortableDeviceService 指针。 否则,这两个指针都支持相同的功能。

位于单线程单元中的应用程序应使用 CLSID_PortableDeviceServiceFTM ,因为这样可以消除接口指针封送处理的开销。 版应用程序仍支持CLSID_PortableDeviceService。

hr = CoCreateInstance(CLSID_PortableDeviceServiceFTM,
                      NULL,
                      CLSCTX_INPROC_SERVER,
                      IID_PPV_ARGS(&pService));
if (SUCCEEDED(hr))
{
    hr = pService->Open(ContactsServicesArray[uiCurrentService], pClientInformation);
    if (FAILED(hr))
    {
        if (hr == E_ACCESSDENIED)
        {
            printf("Failed to Open the service for Read Write access, will open it for Read-only access instead\n");

            pClientInformation->SetUnsignedIntegerValue(WPD_CLIENT_DESIRED_ACCESS, GENERIC_READ);

            hr = pService->Open(ContactsServicesArray[uiCurrentService], pClientInformation);

            if (FAILED(hr))
            {
                printf("! Failed to Open the service for Read access, hr = 0x%lx\n",hr);
            }
        }
        else
        {
            printf("! Failed to Open the service, hr = 0x%lx\n",hr);
        }
    }

IPortableDeviceService 接口

IPortableDeviceValues 接口

IPortableDeviceServiceManager 接口

WpdServicesApiSample