Freigeben über


Koppeln eines Satzes mit der DeviceInformationPairing.Custom-Eigenschaft

Hinweis

Einige Informationen beziehen sich auf Vorabversionen, die vor der kommerziellen Freigabe grundlegend geändert werden können. Microsoft übernimmt hinsichtlich der hier bereitgestellten Informationen keine Gewährleistungen, seien sie ausdrücklich oder konkludent.

Verwenden Sie die Windows.Devices.Enumeration-APIs, um Geräte als Satz zu koppeln.

Windows unterstützt das Koppeln einer Sammlung von Geräten als Gruppe. Die Plattform unterstützt zwei Typen von Sätzen.

  • Automatisch ermittelter Satz Dies geschieht, wenn ein Protokoll (z. B. Bluetooth LE) automatisch andere Endpunkte erkennt, die zum Satz gehören, während ein primärer Endpunkt gekoppelt wird. Während ein Benutzer beispielsweise den rechten Ohrhörer über Bluetooth LE analysiert, kann der Protokollstapel den linken Ohrhörer ermitteln, sodass beide als Satz kombiniert werden können.
  • Expliziter Satz. Diese sind nützlich, wenn ein Gerät über mehrere Protokolle ermittelt wird. Beispielsweise werden IPP-Drucker (Internet Printing Protocol) in der Regel über drei Protokolle ermittelt: IPP, WSD und eSCL. Wenn mehrere Endpunkte für dasselbe Gerät erkannt werden, können sie explizit als Satz gekoppelt werden.

Codebeispiel für einen automatisch erkannten Satz (Bluetooth-Stil)

In diesem Codebeispiel wird die automatisch ermittelte Kopplung (Bluetooth-Stil) mithilfe eines benutzerdefinierten Kopplungsobjekts implementiert. Wie bei einer typischen Implementierung der benutzerdefinierten Kopplung ist ein pairing-requested-Handler erforderlich, um den Kopplungsvorgang zu bearbeiten. In diesem Fall implementiert das Codebeispiel lediglich den Kopplungsvorgang Nur bestätigen. Der neue und interessante Teil fügt einen pairing-set-member-requested-Handler hinzu.

Mit dem set-member-Handler kann die Plattform versuchen, das übergebene Gerät als Satz zu koppeln. Ohne diesen Handler versucht der Protokollstapel nicht, die Member eines Kopplungssatzes aufzuzählen. Das Bluetooth-Protokoll ermittelt Satzmitglieder als Teil der Kopplung, sodass der Satz-Handler irgendwann nach dem Zurückgeben des Vorgangs-Handlers aufgerufen wird. In diesem Ablauf kann der Satz-Handler im Allgemeinen davon ausgehen, dass er einmal aufgerufen wird, nachdem er den Vorgang mit einer festgelegten Liste von Satz-Membern abgewickelt hat. Dies bedeutet, dass das Protokoll während der Kopplung alle möglichen Endpunkte erkennt und später keine weiteren Endpunkte mehr erkennt.

In diesem Codebeispiel werden alle ermittelten Satz-Member synchron mit derselben BtSetPairing-Routine gekoppelt, die zum Koppeln des primären Geräts/Endpunkts verwendet wird. Das parallele Koppeln wird ebenfalls unterstützt und kann für Ihr Szenario effizienter sein. Der Einfachheit halber wird dies jedoch nicht im Codebeispiel gezeigt. Da wir auch die Satz-Member mit einem Satz-Handler koppeln, können sie potenziell rekursiv mehr Satz-Member erzeugen, die gekoppelt werden sollen. In der Regel sieht der Satz-Handler für die erkannten Satz-Member die Erkennung jedoch wahrscheinlich nur dann abgeschlossen, wenn der Satz-Member-Vektor leer ist.

Hinweis

Dieses Codebeispiel wird ohne den Kontext eines größeren Szenarios oder einer größeren App dargestellt. Aber eine App müsste wahrscheinlich nachverfolgen, welche Geräte sie koppelt und welche Kopplungsergebnisse erzielt werden. Dies dient dazu, dass die App einen Eindruck davon erhält, ob der gesamte set-pairing-Vorgang erfolgreich war oder nicht.

Hinweis

Diese APIs sind im Allgemeinen asynchron. Kopplungsvorgänge verfügen über eigene Arbeitsthreads, und Handler werden in verschiedenen Threads aufgerufen. Ihr Code muss nicht so oft blockieren wie in diesem Codebeispiel.

Codebeispiel in 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);
    }
}

Codebeispiel für einen expliziten Satz (IPP-Stil)

In diesem Codebeispiel wird die explizite Satzkopplung mithilfe eines benutzerdefinierten Kopplungsobjekts implementiert. Wie bei einer typischen Implementierung der benutzerdefinierten Kopplung ist ein pairing-requested-Handler erforderlich, um den Kopplungsvorgang zu bearbeiten. In diesem Fall implementiert das Codebeispiel lediglich den Kopplungsvorgang Nur bestätigen. Wie im Bluetooth-Codebeispiel fügt der neue und interessante Teil einen pairing-set-member-requested-Handler hinzu. Der Satz-Member-Handler ermöglicht es der Plattform, Geräte als Satz zu koppeln.

Im Vergleich zum Satz-Kopplungsszenario im Bluetooth-Stil werden in diesem Codebeispiel Geräte explizit zum Satz hinzugefügt. Im Vergleich zu Bluetooth impliziert der Satz-Handler etwas anderes als die Protokolle im Zusammenhang mit der Kopplung von IPP-Druckern. Dies impliziert, dass Clients die Geräteerkennung über die verschiedenen Protokolle durchführen und der PnP-Status und die Druckwarteschlangen, die als Ergebnis der Kopplung aller Gruppenmitglieder erstellt werden, synchronisiert werden sollten.

Um die Implementierung des Codebeispiels einfach zu halten, wird davon ausgegangen, dass zuvor ein Vektor von Satz-Member-Endpunkten erkannt und als Parameter zusammen mit dem primären Gerät übergeben wurde. In einem typischen IPP-Szenario werden Endpunkte beispielsweise in beliebiger Reihenfolge ermittelt. So hätte das primäre Gerät beispielsweise über WSD erkannt werden können; und dann würde der Vektor Geräte enthalten, die über IPP und eSCL erkannte Endpunkte darstellen. Aber jede Kombination ist möglich und gültig. Es fügt Satz-Elemente zum benutzerdefinierten Kopplungsobjekt des primären Geräts im Standard Thread der App hinzu und ruft dann PairAsync auf.

Hinweis

In der Praxis können Satz-Member jederzeit in jedem Thread zu einem benutzerdefinierten Kopplungsprojekt hinzugefügt werden. Vorgänge über ein Protokoll können lange dauern oder sogar blockiert werden, bis eine Zeitüberschreitung auftritt. Daher ist es sinnvoll, sie zu überlappen. Erwägen Sie, die Parallelität der API zu nutzen, um Geräte gleichzeitig hinzuzufügen und zu koppeln. Dies ist sogar möglich, während Sie noch Geräte über das Kabel auflisten. Die Vorteile der Kopplung als Satz gelten weiterhin allgemein.

Bei dieser Implementierung wird der primäre Satz-Member gleichzeitig mit den Satz-Membern gekoppelt. Die Satz-Member werden jeweils synchron im Handler gekoppelt. Aber auch hier können sie parallel kombiniert werden, um eine bessere Effizienz zu erzielen.

Geräteknotenobjekte in PnP werden häufig als Ergebnis der Kopplung erstellt. Bei IPP werden Geräteknoten nach der Kopplung immer für jeden Endpunkt erstellt. Diese Satz-Kopplungs-API synchronisiert die Erstellung von Geräteknoten implizit zwischen Endpunkten in der Gruppe. Im Ablauf dieses Codebeispiels werden alle Geräteknoten synchronisiert, da alle Satz-Member vor dem Start der Kopplung hinzugefügt werden. Weitere Informationen dazu, wie diese API Geräteknoten in PnP synchronisiert, finden Sie im Abschnitt Allgemeiner Kommentar in diesem Thema.

Hinweis

Dieses Codebeispiel wird ohne den Kontext eines größeren Szenarios oder einer größeren App dargestellt. Aber eine App müsste wahrscheinlich nachverfolgen, welche Geräte sie koppelt und welche Kopplungsergebnisse erzielt werden. Dies dient dazu, dass die App einen Eindruck davon erhält, ob der gesamte set-pairing-Vorgang erfolgreich war oder nicht.

Codebeispiel in 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);
    }
}

Allgemeiner Kommentar

Automatisch ermittelte Satz-Kopplung (Bluetooth-Stil)

Diese API ist erforderlich, um die Satz-Kopplung im Bluetooth-Stil durchzuführen, bei der Satz-Member nach der Kopplung des primären Endpunkts vom Protokoll ermittelt werden. Ein einfaches Beispiel könnte ein Satz kabelloser Ohrhörer sein. Sobald die Kopplung des ersten Ohrhörers abgeschlossen ist, informiert das Gerät den PC darüber, dass ein zweites Gerät als Teil des Satzes gekoppelt werden muss. Die benutzerdefinierte Kopplungs-API wird erweitert, um Apps die Behandlung von Satzvorgängen über den neuen add set member status-Handler zu ermöglichen.

Explizite Satzkopplung (IPP-Stil)

Ebenso können Sie diese API auch verwenden, um eine beliebige Gruppe von AEP-Geräten (Zuordnungsendpunkt) als Satz zu koppeln. Mit einem benutzerdefinierten Kopplungsobjekt kann Ihre App dem Kopplungssatz jederzeit in einem beliebigen Thread weitere Endpunkte hinzufügen. Dies ist beabsichtigt, da die Geräteerkennung und die Kopplung über ein Netzwerk für jedes Gerät sehr lange dauern kann. Daher möchten wir diese Vorgänge nicht serialisieren, wenn wir dies vermeiden können.

Es ist besonders hilfreich, wenn Geräte über viele Protokolle ermittelt werden, bei denen die Protokoll- und Gerätestapel nicht einfach koordiniert werden. Beispielsweise wird ein moderner Netzwerkdrucker wahrscheinlich von Windows mit drei verschiedenen Netzwerkprotokollen ermittelt, von denen jeder Zuordnungsendpunkte erzeugt. In diesem Fall ist das Koppeln aller drei Endpunkte als Satz aus einigen Gründen sehr nützlich: Sie vermeidet eine verschwenderische Neuerkennung über die Leitung und erstellt eine einzige, optimierte Druckwarteschlange.

Auch wenn ein Netzwerkdrucker nicht als Satz gekoppelt ist, versucht der Druckspooler trotzdem, eine einzelne Druckwarteschlange pro Benutzer zu erstellen, unabhängig davon, ob er über mehrere Protokolle gekoppelt werden kann. Wenn ein Drucker anfänglich über ein Protokoll gekoppelt ist, versucht das Betriebssystem (BS), es über die anderen unterstützten Protokolle wiederzuentdecken und alle Protokolle zuzuordnen, um doppelte Druckwarteschlangen zu vermeiden. In der Regel kann das Betriebssystem dies schnell und erfolgreich ausführen und eine optimierte Druckwarteschlange erstellen.

Wenn die App jedoch bereits alle Endpunkte für den Drucker entdeckt hat, ist dieser Schritt zur Neuerkennung überflüssig. Und schlimmer noch: es kann zu langen Verzögerungen kommen, bis der Drucker betriebsbereit ist. Wenn die Protokolle außerdem zu asynchron oder verzögert sind, muss der Spooler möglicherweise zusätzliche Druckwarteschlangen für denselben Drucker erstellen, was für Endbenutzer verwirrend ist.

Durch gleichzeitiges Koppeln aller Endpunkte als Satz wird eine potenziell langsame Wiederentdeckung vermieden. Dadurch wird sichergestellt, dass der PnP-Zustand synchronisiert wird und optimale optimierte Druckwarteschlangen erzeugt.

Synchronisierung des Geräteknotens

Wenn die Geräte als Satz mit dieser API gekoppelt werden, wird der resultierende PnP-Gerätestatus bequem synchronisiert. Die API schränkt nicht ein, wann eine App Satz-Member hinzufügen kann. Es gibt jedoch Einschränkungen, wann die Plattform Geräteknoten synchronisieren kann. Die Synchronisierung der Geräteknoten wird blockiert, bis alle Endpunkte im Satz ihre Kopplung abgeschlossen haben. Danach werden alle Geräteknoten für alle Endpunkte gleichzeitig erstellt. Nach diesem Zeitpunkt können Sie weitere Satz-Member zum Satz hinzufügen, die nachfolgende Geräteknotenerstellung wird jedoch nicht blockiert, sondern wird sofort erstellt.

  • Die Geräteknotenerstellung wird synchronisiert, wenn:
    • Satz-Member vor dem Start der Kopplung hinzugefügt werden.
    • Satz-Member hinzugefügt werden, während mindestens einer der Satz-Member nicht abgeschlossen ist.
  • Die Geräteknotenerstellung wird nicht synchronisiert:
    • Jedes Mal, nachdem alle hinzugefügten Satz-Member abgeschlossen wurden.

Aus praktischen Gründen erlaubt die API einer App nicht, den Abschluss des Vorgangs zu steuern, um dieses Verhalten bei der Synchronisierung von Geräteknoten zu beeinflussen. Die größte Annäherung wäre, wenn die App beschließt, den Vorgang abzuschließen. Eine Kopplung kann erst abgeschlossen werden, wenn der Vorgangs-Handler der App zurückgegeben wird. Das ist also die letzte Möglichkeit der App, zu beeinflussen, wann alle Satz-Member abgeschlossen sind.