サービスを開く

サポートされているイベントやメソッドのコンテンツの列挙や説明の取得など、アプリケーションがサービスに対して操作を実行するには、その前にサービスを開く必要があります。 WpdServicesApiSample アプリケーションでは、次の表で説明するインターフェイスを使用して、ServiceEnumeration.cpp モジュールでこのタスクを示します。

インターフェイス 説明
IPortableDeviceServiceManager デバイス上のサービスを列挙するために使用されます。
IPortableDeviceService デバイス サービスへの接続を開くために使用します。
IPortableDeviceValues アプリケーションのクライアント情報を保持するために使用されます。

 

サービスを開くメソッドは 、IPortableDeviceService::Open です。 このメソッドは、サービスのプラグ アンド プレイ (PnP) 識別子と、アプリケーションのクライアント情報を含む IPortableDeviceValues オブジェクトの 2 つの引数を受け取ります。

特定のサービスの 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 に対して 2 つの CLSID がサポートされています。 CLSID_PortableDeviceService は、フリースレッド マーシャラーを集計しない IPortableDeviceService ポインターを返します。 CLSID_PortableDeviceServiceFTM は、フリースレッド マーシャラーを集計する IPortableDeviceService ポインターを返す新しい CLSID です。 それ以外の場合は、両方のポインターで同じ機能がサポートされます。

シングル スレッド アパートメントに存在するアプリケーションでは 、インターフェイス ポインター マーシャリングのオーバーヘッドが排除されるため、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