次の方法で共有


DeviceInformationPairing.Custom プロパティを使用してセットをペアリングする

Note

一部の情報はリリース前の製品に関する事項であり、正式版がリリースされるまでに大幅に変更される可能性があります。 Microsoft はここに示されている情報について、明示か黙示かを問わず、一切保証しません。

デバイスをセットとしてペアリングするには、Windows.Devices.Enumeration API を使用します。

Windows では、デバイスのコレクションをセットとしてペアリングすることができます。 プラットフォームでは、次の 2 種類のセットがサポートされています。

  • 自動検出セット。 これは、プライマリ エンドポイントのペアリング中に、セットに属する他のエンドポイントがプロトコル (Bluetooth LE など) によって自動的に検出された場合に発生します。 たとえば、ユーザーが Bluetooth LE 経由で右側のイヤホンをペアリングしているときに、プロトコル スタックで左側のイヤホンが検出されることがあります。この場合、両方をセットとして一緒にペアリングできます。
  • 明示的セット。 これらは、デバイスが複数のプロトコルで検出される場合に便利です。 たとえば、インターネット印刷プロトコル (IPP) プリンターは、通常、IPP、WSD、eSCL の 3 つのプロトコルで検出されます。 同じデバイスから複数のエンドポイントが検出される場合は、それらを明示的にまとめてセットとしてペアリングできます。

自動検出セットのコード例 (Bluetooth スタイル)

このコード例では、カスタム ペアリング オブジェクトを使用して、自動検出 (Bluetooth スタイル) セットのペアリングを実装します。 カスタム ペアリングの一般的な実装と同様に、ペアリング手続きを処理するためにペアリング要求ハンドラーが必要です。 このコード例では、確認のみのペアリング手続きだけを実装しています。 注目すべき違いは、ペアリング セット メンバー要求ハンドラーを追加している点です。

セット メンバー ハンドラーがあると、プラットフォームは、渡されたデバイスをセットとしてペアリングしようと試みます。 このハンドラーがない場合、プロトコル スタックは、ペアリング セットのメンバーの列挙を試行しません。 Bluetooth プロトコルは、ペアリングの最終処理の一部としてセット メンバーを検出します。したがって、セット ハンドラーは手続きハンドラーが戻った後に呼び出されます。 このフローでは、セット ハンドラーは一般に、固定リストのセット メンバーで手続きが処理された後、1 回だけ呼び出されることが想定されます。つまり、プロトコルは、ペアリング中に検出できるエンドポイントをすべて検出し、後から追加で検出することはありません。

このコード例では、検出されたすべてのセット メンバーを、プライマリ デバイス/エンドポイントのペアリングに使用されるのと同じ BtSetPairing ルーチンによって同期的にペアリングします。 メンバーを並列でペアリングすることもサポートされ、それによってシナリオの効率が向上する可能性があります。 ただしこれは、簡潔にするためにコード例には示されていません。 セット メンバーのペアリングはセット ハンドラーでも行われるため、ペアリングする追加のセット メンバーが再帰的に生成される可能性があります。 ただし、通常、検出されたセット メンバーに対して呼び出されるセット ハンドラーで通知されるのは、セット メンバーのベクターが空の検出完了のみであることがほとんどです。

Note

このコード例では、大規模なシナリオやアプリのコンテキストは考慮されていません。実際のアプリでは、多くの場合、ペアリングしようとしているデバイスとペアリングの結果を追跡する必要があります。 これは、セット ペアリングの操作全体が成功したかどうかをアプリで把握するためです。

Note

これらの API は一般的に非同期です。 ペアリング操作には独自のワーカー スレッドがあり、ハンドラーは別のスレッドで呼び出されます。 実際のコードでは、このコード例ほど頻繁にブロックする必要はありません。

C++/WinRT でのコードの例

void PairingTests::BtSetPairing(DeviceInformation device)
{
    DevicePairingKinds ceremonies = DevicePairingKinds::ConfirmOnly;
    auto customPairing = device.Pairing().Custom();
    event_revoker ceremonyEventToken = customPairing.PairingRequested(
        { this, &PairingTests::PairingRequestedHandler });
    event_revoker setEventToken = customPairing.PairingSetMembersRequested(
        { this, &PairingTests::PairingSetMembersRequestedHandler });

    DevicePairingResult result = customPairing.PairAsync(ceremonies).get();

    if (DevicePairingResultStatus::Paired == result.Status()) // Pairing worked.
    else // Handle pairing failure.
}

void PairingTests::PairingRequestedHandler(DeviceInformationCustomPairing const&,
    DevicePairingRequestedEventArgs const& args)
{
    switch (args.PairingKind())
    {
    case DevicePairingKinds::ConfirmOnly:
        args.Accept();
        break;
    default:
        // This code example doesn't implement other ceremonies.
        // The handler wouldn't be called for ceremonies that the app didn't register.
    }
}

void PairingTests::PairingSetMembersRequestedHandler(DeviceInformationCustomPairing
    const&, DevicePairingSetMembersRequestedEventArgs const& args)
{
    switch (args.Status())
    {
    case DevicePairingAddPairingSetMemberStatus::SetDiscoveryCompletedByProtocol:
        // This is the expected result if we started set pairing 
        // a Bluetooth device. Note: there still might be no set members.
        break;
    case DevicePairingAddPairingSetMemberStatus::SetDiscoveryPartiallyCompletedByProtocol:
        // The protocol enumerated some but not all set members.
        break;
    case DevicePairingAddPairingSetMemberStatus::SetDiscoveryNotAttemptedByProtocol:
        // Not expected for Bluetooth.
        // This constant implies that the protocol likely doesn't support set-pairing.
    default:
        // The other constants aren't expected in an auto-discovered Bluetooth set scenario.
        // Error handling can go here.
    }

    for (auto setMember : args.PairingSetMembers())
    {
        BtSetPairing(setMember);
    }
}

明示的セットのコード例 (IPP スタイル)

このコード例では、カスタム ペアリング オブジェクトを使用して、明示的セットのペアリングを実装します。 カスタム ペアリングの一般的な実装と同様に、ペアリング手続きを処理するためにペアリング要求ハンドラーが必要です。 このコード例では、確認のみのペアリング手続きだけを実装しています。 Bluetooth のコード例と同じく、注目すべき違いは、ペアリング セット メンバー要求ハンドラーを追加している点です。 セット メンバー ハンドラーがあると、プラットフォームは、デバイスをセットとしてペアリングしようと試みます。

Bluetooth スタイルのセット ペアリング シナリオと比較して、このコード例では、デバイスを明示的にセットに追加します。 Bluetooth と比べると、IPP プリンターのペアリングに関連するプロトコルでは、セット ハンドラーが少し異なります。 これは、クライアントがさまざまなプロトコル経由でデバイスの検出を処理しており、すべてのセット メンバーのペアリング結果として作成された PnP 状態と印刷キューを同期する必要があることを示しています。

コード例の実装をシンプルにするために、ここでは、セット メンバー エンドポイントのベクターが事前に検出されていて、プライマリ デバイスと共にパラメーターとして渡されるものと想定しています。 たとえば、一般的な IPP シナリオでは、エンドポイントは任意の順序で検出されます。 したがって、たとえばプライマリ デバイスは WSD 経由で検出され、ベクターには IPP や eSCL 経由で検出されたエンドポイントを表すデバイスが含まれることがあります。 どのような組み合わせも可能であり、有効です。 アプリのメイン スレッドで、セット メンバーをプライマリ デバイスのカスタム ペアリング オブジェクトに追加し、PairAsync を呼び出します。

Note

実際には、セット メンバーのカスタム ペアリング オブジェクトへの追加は、任意のタイミングかつ任意のスレッドで行われる可能性があります。 プロトコル経由の操作は長い時間を要したり、タイムアウトするまでブロックされたりする場合があるため、オーバーラップで処理することが役立ちます。 API の並列処理を利用して、デバイスの追加とペアリングを同時に行うことを検討してください。 これは、ネットワーク経由でデバイスを列挙している間でも可能です。 デバイスをセットとしてペアリングする利点は、その場合も一般的に適用されます。

この実装では、プライマリ セット メンバーはセット メンバーと同時にペアリングされます。 セット メンバーは、ハンドラー内で一度に 1 つずつ同期的にペアリングされます。 ただし、ここでも効率化のために並列でペアリングすることが可能です。

ペアリングの結果として、PnP のデバイス ノード オブジェクトが作成されることがよくあります。 IPP の場合は、ペアリング後、エンドポイントごとに常にデバイス ノードが作成されます。 このセット ペアリング API は、セット内のエンドポイント間でデバイス ノードの作成を暗黙的に同期します。 このコード例のフローでは、ペアリングの開始前にすべてのセット メンバーが追加されるため、すべてのデバイス ノードが同期されることになります。 この API によって PnP のデバイス ノードがどのように同期されるかの詳細については、このトピックの「全般的な解説」セクションを参照してください。

Note

このコード例では、大規模なシナリオやアプリのコンテキストは考慮されていません。実際のアプリでは、多くの場合、ペアリングしようとしているデバイスとペアリングの結果を追跡する必要があります。 これは、セット ペアリングの操作全体が成功したかどうかをアプリで把握するためです。

C++/WinRT でのコードの例

void PairingTests::IppSetPairing(DeviceInformation device,
    std::vector<DeviceInformation> const& setMemberDevices)
{
    DevicePairingKinds ceremonies = DevicePairingKinds::ConfirmOnly;
    auto customPairing = device.Pairing().Custom();
    event_revoker ceremonyEventToken = customPairing.PairingRequested({ this,
                     &PairingTests::PairingRequestedHandler });
    event_revoker setEventToken = customPairing.PairingSetMembersRequested({ this,
                  &PairingTests::PairingSetMembersRequestedHandler });

    if (setMemberDevices)
    {
        for (auto setDevice : setMemberDevices)
        {
            customPairing.AddPairingSetMember(setDevice);
        }
    }

    DevicePairingResult result = customPairing.PairAsync(ceremonies).get();

    if (DevicePairingResultStatus::Paired == result.Status()) // Pairing worked.
    else // Handle pairing failure.
}

void PairingTests::PairingRequestedHandler(DeviceInformationCustomPairing const&,
    DevicePairingRequestedEventArgs const& args)
{
    switch (args.PairingKind())
    {
    case DevicePairingKinds::ConfirmOnly:
        args.Accept();
        break;
    }
}

void PairingTests::PairingSetMembersRequestedHandler(DeviceInformationCustomPairing const&,
    DevicePairingSetMembersRequestedEventArgs args)
{
    switch (args.Status())
    {
    case DevicePairingAddPairingSetMemberStatus::AddedToSet:
        // This is the expected result of adding a set member(s) to
        // a Bluetooth device. Note: there still might be no set members.
        break;
    case DevicePairingAddPairingSetMemberStatus::CouldNotBeAddedToSet:
        // Means we failed to add set member(s).
        break;
    case DevicePairingAddPairingSetMemberStatus::SetDiscoveryNotAttemptedByProtocol:
    default:
        // The other constants aren't expected in an auto-discovered Bluetooth set scenario.
        // Error handling can go here.
    }

    for (auto setMember : args.PairingSetMembers())
    {
        IppSetPairing(setMember, nullptr);
    }
}

全般的な解説

自動検出 (Bluetooth スタイル) セットのペアリング

この API は Bluetooth スタイルのセット ペアリングを実現するために必要です。このスタイルのセット ペアリングでは、プライマリ エンドポイントがペアリングされた後で、プロトコルによってセット メンバーが検出されます。 単純な例として、ワイヤレス イヤホンのセットがあります。 最初のイヤホンのペアリングが完了すると、デバイスは、セットの一部としてペアリングする 2 つ目のデバイスがあることを PC に通知します。 カスタム ペアリング API は、新しいセット メンバー ステータスの追加ハンドラーを通じてアプリがセット操作を処理できるように拡張されています。

明示的 (IPP スタイル) セットのペアリング

同様に、この API を使用して、関連付けエンドポイント (AEP) デバイスのグループをセットとしてペアリングすることもできます。 カスタム ペアリング オブジェクトを使用すると、アプリはいつでも任意のスレッドでペアリング セットに他のエンドポイントを追加できます。 このような仕様になっているのは、ネットワーク経由でのデバイスの検出とペアリングにはデバイスごとに長い時間がかかる可能性があり、その操作の連続実行を回避できる場合は回避した方が望ましいためです。

プロトコルとデバイス スタックを簡単には統合できない状況で、多数のプロトコルでデバイスを検出する場合は、セットでのペアリングが特に役立ちます。 たとえば、最新のネットワーク プリンターは、Windows によって 3 つの異なるネットワーク プロトコルで検出され、それぞれが関連付けエンドポイントを生成する可能性があります。 この場合、3 つのエンドポイントのすべてをセットとしてペアリングすると、ネットワーク経由で無駄な再検出が行われるのを回避でき、単一の合理化された印刷キューが作成されるため、非常に便利です。

ネットワーク プリンターがセットとしてペアリングされない場合でも、印刷スプーラーは、プリンターが複数のプロトコルでペアリングできるかどうかにかかわらず、ユーザーごとに単一の印刷キューを作成しようとします。 プリンターが最初に 1 つのプロトコルでペアリングされた場合、オペレーティング システム (OS) は、印刷キューの重複を防ぐために、サポートされている他のプロトコルで再検出を試み、検出されたすべてのプロトコルで関連付けを行います。 OS は通常、これをすばやく正常に実行し、1 つの合理化された印刷キューを生成することができます。

ただし、アプリで既にプリンターのすべてのエンドポイントが検出されている場合、この再検出の手順は無駄になります。 さらに悪いことに、これにより、プリンターの使用準備ができる前に長い遅延が発生することがあります。 また、プロトコルが極端に同期されていないか遅延していると、スプーラーでは同じプリンター用に追加の印刷キューを作成することが必要になる場合があり、エンド ユーザーの混乱を招きます。

すべてのエンドポイントをセットとして一度にペアリングすれば、時間がかかる可能性のある再検出を回避できます。 これにより、PnP 状態が同期され、合理化された最適な印刷キューが生成されます。

デバイス ノードの同期

この API を通じてデバイスがセットとしてペアリングされると、結果の PnP デバイス状態は適切に同期されます。 API では、アプリがいつセット メンバーを追加できるかに関する制約はありませんが、プラットフォームがいつデバイス ノードを同期できるかについては制限があります。 デバイス ノードの同期は、セット内のすべてのエンドポイントのペアリングが完了するまでブロックされます。 その後で、すべてのエンドポイントのすべてのデバイス ノードが一度に作成されます。 この時点以降もセットにセット メンバーを追加できますが、その場合は後続のデバイス ノードの作成はブロックされず、すぐに作成されます。

  • 次の状況では、デバイス ノードの作成が同期されます
    • ペアリングの開始前にセット メンバーが追加されたとき。
    • 少なくとも 1 つのセット メンバーの最終処理が完了していないうちにセット メンバーが追加されたとき。
  • 次の状況では、デバイス ノードの作成は同期されません
    • 追加されたすべてのセット メンバーの最終処理が完了した後。

実際問題として、この API では、デバイス ノードの同期の動作に関与しようとしても、手続きの最終処理がいつ完了するかをアプリで制御することはできません。 最も近いタイミングは、アプリが手続きを完了することにしたときです。 ペアリングの処理はアプリの手続きハンドラーが戻るまで完了できないため、すべてのセット メンバーの最終処理が完了するタイミングにアプリから影響を与えるとしたら、そのときが最後の機会となります。