WinRT-Typsystem (Windows-Runtime)

Allgemeine Hinweise

Alle Typen , außer für die grundlegenden Typen, müssen in einem Namespace enthalten sein. Es ist nicht gültig, dass sich ein Typ im globalen Namespace befindet.

Typen, die von Windows bereitgestellt werden, sind unter dem Windows.* Namespace enthalten. WinRT-Typen, die von Windows nicht bereitgestellt werden (einschließlich WinRT-Typen, die von anderen Teilen von Microsoft bereitgestellt werden), müssen in einem anderen Namespace als Windows.*leben.

Mit Ausnahme von Schnittstellen müssen alle WinRT-Typen über öffentliche Sichtbarkeit verfügen. WinRT-Schnittstellen können optional über private Sichtbarkeit verfügen. Alle anderen benutzerdefinierten WinRT-Typen (Strukturen, Klassen, Aufzählungen, Stellvertretungen, Attribute) müssen öffentliche Sichtbarkeit haben.

WinRT unterstützt keine geschachtelten Typen. Kein WinRT-Typ kann einen anderen Typ einschließen; Kein WinRT-Typ kann innerhalb eines anderen Typs geschachtelt werden.

Nicht alle Aspekte des WinRT-Typsystems stehen Ihnen als Drittanbieterentwickler zur Verfügung.

  • WinRT unterstützt die Parameterisierung von Schnittstellen und Stellvertretungen. In dieser Version unterstützt WinRT jedoch keine Definition von parameterisierten Typen von 3. Parteien. Nur die parameterisierten Typen, die im System im Windows.* -Namespace enthalten sind, werden unterstützt.

  • WinRT unterstützt die Klassenkomposition als Laufzeitvererbungsmechanismus. In dieser Version unterstützt WinRT jedoch keine Definition einer stammkomposablen Klasse. Nur die in dem System im Windows.* Namespace enthaltenen Stammklassen werden unterstützt.

WinRT-Namespaces und Typnamen sind Groß- und Kleinschreibung, aber unempfindlichkeit, ähnlich wie das Windows Dateisystem und die Windows Registrierung. Dies bedeutet, dass Sie keine Namespaces oder Typnamen haben können, die nur nach Fall variieren. Sie können z. B. weder Foo.SomeType noch foo haben. AnotherType, oder Sie können sowohl Foo.SomeType als auch Foo.someType haben.

Ein WinRT-Bezeichner muss der folgenden Grammatik entsprechen. Beachten Sie, dass nur in Unicode 3.0 und früher definierte Zeichen unterstützt werden.

    identifier-or-keyword: 
        identifier-start-character   identifier-continuation-characters* 
    identifier-start-character: 
        letter-character
        underscore (U+005F) 
    identifier-continuation-characters: 
        identifier-continuation-character
        identifier-continuation-characters   identifier-continuation-character 
    identifier-continuation-character: 
        identifier-start-character 
        decimal-digit-character
        connecting-character
        combining-character
        formatting-character 
    letter-character: 
        A Unicode 3.0 character of classes Lu, Ll, Lt, Lm, Lo, or Nl 
    combining-character: 
        A Unicode 3.0 character of classes Mn or Mc 
    decimal-digit-character: 
        A Unicode 3.0 character of the class Nd 
    connecting-character: 
        A Unicode 3.0 character of the class Pc 
    formatting-character: 
        Zero Width Non-Joiner (U+200C)
        Zero Width Joiner (U+200D)

Parametrisierte Typen

WinRT unterstützt die Typparameterisierung von Schnittstellen und Stellvertretungen. Die parameterisierten Typen ermöglichen es, eine Familie von Schnittstellen zu definieren, die polymorph in Programmiersprachen verarbeitet werden können, die parametrische Polymorphismus unterstützen.

Eine parameterisierte Typ-Instanziierung tritt auf, wenn ein parameterisierter Typ mit einer Argumentliste von Typen in einem Typkontext angegeben wird, z. B. eine Methodenparameterposition. Instanziiert beispielsweise HRESULT foo(X<Y> x) den von X benannten parameterisierten Typ mit dem Typ Y als erstes und einziges Typargument.

Eine nichtparameterisierte WinRT-Schnittstelle oder ein Stellvertretung wird einer GUID zugewiesen, um die zugrunde liegende Schnittstelle eindeutig als anders als andere Schnittstellen desselben Objekts zu identifizieren. Eine parameterisierte Schnittstelle (z. B. ) oder Stellvertretung (zIVector<T>EventHandler<T>. B. ) wird stattdessen einer parameterisierten Schnittstellen-ID (PIID) zugewiesen, die eine GUID ist, die diesen parameterisierten Typ eindeutig identifiziert. Dies ist kein IID. Diese GUID wird in der Erstellung von IIDs für parameterisierte Typinstanzen (z IVector<int>. B. ) verwendet.

Parameterisierte Typargumentliste

Diese WinRT-Typen dürfen in der Argumentliste für einen parameterisierten Typ angezeigt werden.

  • WinRT-grundlegende Typen (z. B. Boolean, Int32, String, Guid usw.)
  • WinRT-Aufzählungen
  • WinRT-Strukturen
  • WinRT-Schnittstellen
  • WinRT-Stellvertretungen
  • WinRT-Laufzeitklassen
  • Andere parameterisierte Typ-Instanziationen (z IVector<IVector<int>>. B. ) Jeder andere Typ ist verboten, in einer parameterisierten Typargumentliste anzuzeigen. Beispiel: Arrays.

Parameterisierte Typinstanzen

Eine parameterisierte Typinstanz kann in jedem Kontext angezeigt werden, in dem ein nicht parameterisierter Typ angezeigt werden kann. Eine parameterisierte Schnittstelleninstanz kann an einer beliebigen Stelle verwendet werden, z. B. in der Liste der Schnittstellen, die von einer Laufzeitklasse implementiert werden. Eine parameterisierte Stellvertretungsinstanz kann an einer beliebigen Stelle verwendet werden, z. B. in der Definition eines Ereignisses.

Ein parameterisierter Typparameter kann angezeigt werden: in der parameterisierten Schnittstelle oder Stellvertretungsdefinition; oder jeder Ort, an dem ein normaler Typ normalerweise angezeigt werden kann. Wenn ein Parameter angezeigt wird, bei dem nur eine Schnittstelle angezeigt werden kann, ist dieser Parameter auf eine Schnittstelle beschränkt. Wenn ein Parameter in einem Kontext angezeigt wird, in dem ein beliebiger Typ angezeigt werden kann, ist dieser Parameter nicht eingeschränkt; und so weiter. Argumente für parameterisierte Typinstanzen müssen alle solchen Einschränkungen erfüllen.

Guid-Generation für parameterisierte Typen

Der Guid-Generation-Algorithmus muss diese Anforderungen erfüllen.

  • Wenn ein parameterisierter Typ zweimal mit den gleichen Argumenten instanziiert wird, müssen beide Instanziationen demselben Schnittstellen- oder Stellvertretungstext und demselben IID zugewiesen werden.
  • Wenn zwei verschiedene parameterisierte Typen instanziiert werden, auch mit den gleichen Argumenten, muss es statistisch unwahrscheinlich sein, dass sie demselben IID zugewiesen werden.
  • Wenn ein parameterisierter Typ zweimal instanziiert wird, aber mit unterschiedlichen Argumenten muss es statistisch unwahrscheinlich sein, dass die beiden Instanziationen demselben IID zugewiesen werden.

Hinweis

Es ist nicht zulässig, dass ein parameterisierter Typ mit derselben Instanziierung als Argument instanziiert werden kann oder als Argument für einen anderen parameterisierten Typ, der in der Argumentliste angezeigt wird (das heißt, Zirkelinstanziation). Wenn X = Foo<Y>beispielsweise , und Y = Foo<X>, Nicht-Zirkelität verletzt wurde. Wenn X = Foo<Y> und Y = Foo<int>, dann wurde jedoch keine Zirkelität beibehalten.

Der Instanziierungsalgorithmus ist wie folgt.

  1. Jeder parameterisierte Typ wird einer parameterisierten Schnittstellen-ID durch seinen Autor zugewiesen – abgekürzt PIID. Beachten Sie, dass eine PIID keine IIDs ist, noch nicht als Argument an QueryInterface übergeben wird. Der Autor muss sicherstellen, dass die PIID für den parameterisierten Typ eindeutig ist.
  2. Die Typsignatur für einen Basistyp ist eine ASCII-Oktetzeichenfolge (siehe die folgende Tabelle). Int32 ist z. B. "i4".
  3. Die Typsignatur für eine Schnittstelle, die keine parameterisierte Schnittstelleninstanz ist, ist ihre IID-codiert in ASCII in gestrichelter Form und durch geschweifte Klammern getrennt. Beispiel: „{00000000-0000-0000-0000-000000000000}“.
  4. Die Typsignatur für eine Stellvertretung, die keine parameterisierte Stellvertretungsinstanz ist, ist die Zeichenfolge "Delegate", und dann die IID als Schnittstellen. Die detaillierte Grammatik wird als nächstes angezeigt.
  5. Die Guid für einen parameterisierten Typ wird entsprechend dieser Grammatik berechnet.
    • gemäß UUID rfc 4122 berechnen Sie den generierten Ver 5 Sha-1-Hash von signature_octets– dies verwendet eine einzelne winrt pinterface/pintergroup guid als Namespace wie in rfc 4122/4.3 beschrieben, und die Signatur der Pinterface/Pintergroup und die Args, die sie als Namezeichenfolge instanziiert wird.
    • die Pinterface-Instanziation wird dieser Guid zugewiesen und die Signatur von 4.
    signature_octets => guid_to_octets(wrt_pinterface_namespace) string_to_utf8_octets(ptype_instance_signature)

        wrt_pinterface_namespace => "11f47ad5-7b73-42c0-abae-878b1e16adee"

        ptype_instance_signature => pinterface_instance_signature | pdelegate_instance_ signature

        pinterface_instance _signature => "pinterface(" piid_guid  ";" args ")"

        pdelegate_instance _signature => "pinterface(" piid_guid ";" args ")"

        piid_guid => guid

        args => arg | arg ";" args

        arg => type_signature

        type_signature => base_type_identifer | com_interface_signature | interface _signature | delegate_signature  | interface_group_signature | runtime_class_signature | struct_signature | enum_signature | pinterface_instance_signature | pdelegate_instance_signature
        com_interface_signature => "cinterface(IInspectable)"

        base_type_identifier is defined below

        interface_signature => guid

        interface_group_signature => "ig(" interface_group_name ";" default_interface ")"

        runtime_class_signature => "rc(" runtime_class_name ";" default_interface ")"

        default_interface => type_signature

        struct_signature => "struct(" struct_name ";" args ")"

        enum_signature => "enum(" enum_name ";" enum_underlying_type ")"

        enum_underlying_type => type_signature

        delegate_signature => "delegate(" guid ")"

        guid => "{" dashed_hex "}"

        dashed_hex is the format that uuidgen writes in when passed no arguments.

            dashed_hex => hex{8} "-" hex{4} "-" hex{4} "-" hex{4} "-" hex{12}

            hex => [0-9a-f]
  1. Wenn eine P-Typ-Instanziierung als Argument an ein weiteres Pinterface übergeben wird, wird die signatur, die von Schritt 3 berechnet wird, als Typsignatur im Grammatikelement "pinterface_instance_signature" oder "pdelegate_instance_signature" verwendet.

Diese Namen werden für Basistypen verwendet, wenn sie angezeigt werden.

  • UInt8 karten zu "u1"
  • Int32 ordnet "i4" zu
  • UInt32 ordnet "u4 " zu
  • Int64 bezieht sich auf "i8"
  • UInt64 bezieht sich auf "u8"
  • Einzelne Karten zu "f4"
  • Doppelte Karten zu "f8"
  • Boolescher Karten zu "b1"
    • Beachten Sie, dass Sie zum Abrufen der Unterstützung von Boolean-Typparameternwchar_t als integrierten Typ hinzufügen /Yc:wchar_t müssen.
  • Char16 entspricht "c2"
  • Zeichenfolgen werden mit "string" zugeordnet.
  • Guid-Karten zu "g16"

Die obigen Namen sind groß- und kleinschreibungsempfindlich. Mit Ausnahme der Zeichenfolge verwendet der Typname ein einzelnes Zeichen, um die Art von Daten anzugeben, gefolgt von der Größe in Bytes. Diese Namen wurden ausgewählt: kurz zu sein (um große Größen in der Struktur von Typsignaturen zu vermeiden); nicht verwirrend ähnlich wie der WinRT-Name, der RIDL-Name oder der Sprachprojektionsname für jeden Typ; und bleiben noch ungefähr menschenlesbar.

Für enum_type_signature ist der einzige gültige Wert "underlying_type" das von Int32 oder UInt32.

Für struct_type_signature ist Args eine Inreihenliste von type_signatures für die Felder der Struktur. Diese können Basistypen oder andere Strukturtypen sein.

Struct_name und enum_name sind Namespacequalifizierte, wobei "." als Trennzeichen verwendet wird. Beispielsweise wird "namespace X { struct A{ int; }" zu "struct(X.A;i4)".

Default_interface muss die Schnittstelle, p-Interface-Instanz, Stellvertretung oder P-Stellvertretungsinstanz sein, die im Laufzeitklassen- oder Schnittstellengruppentext angegeben wurde, wobei das IDL -Attribut '[Default]' verwendet wurde.

Beachten Sie, dass benutzerdefinierte Attribute ignoriert werden; angenommen, dass es keine Auswirkungen auf die Marschierung hat.

Versionsverwaltung

Alle WinRT-Typen außer grundlegenden Typen müssen über ein Version-Attribut verfügen. Sprachprojektionen verwenden die Versionsattributinformationen, um abwärtskompatibilität zu ermöglichen, und für Lichtszenarien. Drittanbietertypen müssen ein Versionsattribut enthalten, müssen jedoch von Sprachprojektionen ignoriert werden. WinRT-Komponenten von Drittanbietern werden ausschließlich in der App verpackt, sodass sie die Version nie unabhängig von der App selbst ändern können.

Das Version-Attribut kann optional auf Schnittstellenelemente (Methoden, Eigenschaften und Ereignisse) angewendet werden. Dies ist für die allgemeine Klassenerstellung in C#/VB und C++/CX vorgesehen. Versionsattribute für Schnittstellenelemente, auch Windows Systemschnittstellenelemente, müssen zur Laufzeit durch Sprachprojektionen ignoriert werden.

Das Version-Attribut enthält einen nicht signierten 32-Bit-Ganzzahlkonstruktorparameter. Für Windows WinRT-Typen ist dieser Wert der NTDDI-Wert für die Version von Windows der zugeordneten Typkonstrukte wurde zuerst definiert. Für Drittanbietertypen ist die Bedeutung dieses Werts bis zum Autor des Typs.

Windows Systemstruktur, Stellvertretungen und Schnittstellen sind nach der Definition unveränderlich. Sie können in keiner nachfolgenden Windows Version geändert werden.

Windows Systemenumen und Laufzeitklassen sind additiv versionierbar. Aufzählungen können in nachfolgenden Windows Versionen neue Enumerationswerte hinzufügen. Klassen können neue implementierte Schnittstellen (einschließlich statischer, Aktivierungsfabrik, Kompositionsfabrik, überschreibender und geschützter Schnittstellen) in nachfolgenden Windows Versionen hinzufügen. Weitere Details zur additiven Versionsverwaltung sind in den Abschnitten für Enumerationen und Laufzeitklassen enthalten.

Namespaces

Ein Namespace ist ein Benennungsbereich, der zum Organisieren von Code verwendet wird, und um Benennungskonflikte zu vermeiden. Alle benannten Typen im WinRT-Typsystem (Enumerationen, Strukturen, Stellvertretungen, Schnittstellen und Laufzeitklassen) leben in einem Namespace. Ein Namespace kann andere Namespaces enthalten.

Grundlegende Typen

Das WinRT-Typsystem enthält einen Kernsatz integrierter Grundtypen.

WinRT-Typ Typbeschreibung
Int16 eine 16-Bit-Ganzzahl
Int32 eine 32-Bit-ganzzahl
Int64 eine 64-Bit-Ganzzahl
UInt8 eine 8-Bit-ganzzahl ohne Vorzeichen
UInt16 eine 16-Bit-ganzzahl ohne Vorzeichen
UInt32 eine 32-Bit-Ganzzahl ohne Vorzeichen
UInt64 eine 64-Bit-ganzzahl ohne Vorzeichen
Single eine 32-Bit-IEEE 754-Gleitkommanummer
Double eine 64-Bit-IEEE 754-Gleitkommanummer
Char16 ein nicht numerischer 16-Bit-Wert, der eine UTF-16-Codeeinheit darstellt
Boolean ein boolescher 8-Bit-Wert
String eine unveränderliche Sequenz von Char16 , die zum Darstellen von Text verwendet wird
Guid Eine 128-Bit-Standard-Guid

Enumerationen

Ein Enumerationstyp ist ein eindeutiger Werttyp mit einem Satz benannter Konstanten.

Jeder Enumerationstyp weist einen entsprechenden integralen Typ auf, der als zugrunde liegenden Typ des Enumerationstyps bezeichnet wird. Die einzigen gesetzlichen Enumerationstypen in WinRT sind Int32 und UInt32.

Eine Enumeration mit einem zugrunde liegenden Typ von UInt32 muss das FlagsAttribute tragen. Eine Enumeration mit einem zugrunde liegenden Typ von Int32 darf das FlagsAttribute nicht tragen.

Eine Aufzählung muss über öffentliche Sichtbarkeit verfügen.

Enumerationsversionsverwaltung

Eine Enumeration ist additiv versionierbar. Nachfolgende Versionen einer bestimmten Enumeration können Werte hinzufügen (auch als benannte Konstanten bezeichnet). Vorhandene Werte werden möglicherweise nicht entfernt oder geändert. Enumerationswerte tragen optional das VersionAttribute-Objekt, um zu unterscheiden, wann bestimmte Werte dem Enumerationstyp hinzugefügt wurden. Enumerationswerte ohne VersionAttribute gelten als denselben Versionswert wie der eingeschlossene Enumerationstyp.

Strukturen

Eine Struktur ist ein Datensatztyp mit einem oder mehreren Feldern. Structs werden immer übergeben und nach Wert zurückgegeben. Strukturfelder dürfen nur Grundtypen, Enumerationen, Strukturen, Zeichenfolgen und IReference<T> sein (letztere zwei sind die einzigen beiden heap-zugeordneten Feldtypen).

Structs müssen öffentliche Sichtbarkeit haben.

Im Allgemeinen muss eine Struktur mindestens ein Feld aufweisen (es gibt seltene Ausnahmen, z. B. Typen, die Metadatenverträge und Attribute darstellen). Alle Felder einer Struktur müssen öffentlich sein.

Eine Struktur kann nicht generisch oder parametrisiert werden.

Schnittstellen

Eine Schnittstelle ist ein Vertrag, der aus einer Gruppe verwandter Typmitglieder besteht, deren Verwendung definiert ist, deren Implementierung jedoch nicht erfolgt. Eine Schnittstellendefinition gibt die Elemente der Schnittstelle an– Methoden, Eigenschaften und Ereignisse. Es gibt keine Implementierung, die einer Schnittstelle zugeordnet ist.

Nicht parametrisierte Schnittstellen müssen eine eindeutige Schnittstellen-ID (aka IID) aufweisen, die über eine GuidAttribute angegeben wird. Eine parametrisierte Schnittstelle muss über eine eindeutige parametrisierte Schnittstellen-ID (auch als PIID bezeichnet) verfügen, die über eine GuidAttribute angegeben wird. Die PIID wird verwendet, um eine IID für eine bestimmte parametrisierte Schnittstelleninstanz über den oben angegebenen Algorithmus zu generieren.

Eine Schnittstelle kann öffentliche oder private Sichtbarkeit haben. Dies spiegelt die Tatsache wider, dass einige Schnittstellen freigegebene Verträge darstellen, die von mehreren WinRT-Klassen implementiert werden, während andere Schnittstellen Member darstellen, die von einer einzelnen WinRT-Klasse implementiert werden. Eine private Sichtbarkeitsschnittstelle muss die WinRT-Klasse angeben, die ausschließlich über das ExclusiveToAttribute erfolgt. Private Schnittstellen können nur von der winRT-Klasse implementiert werden, die in "ExclusiveToAttribute" angegeben ist.

IInspectable und IUnknown

Wenn es um Schnittstellen geht, hat WinRT keine Vorstellung von Vererbung. Stattdessen gibt es die Idee, dass eine Schnittstelle eine andere Schnittstelle erfordern kann. Weitere Informationen, insbesondere über das Schlüsselwort MIDL 3.0 requires , finden Sie unter MIDL 3.0-Schnittstellen.

Alle WinRT-Schnittstellen erfordern implizit IInspectable; und wiederum erfordert IInspectable IUnknown. IUnknown definiert drei Methoden: QueryInterface, AddRef und Release gemäß herkömmlicher COM-Verwendung. IInspectable definiert zusätzlich zu den IUnknown-Methoden drei Methoden: GetIids, GetRuntimeClassName und GetTrustLevel. Mit diesen drei Methoden kann der Client des Objekts Informationen zum Objekt abrufen. Insbesondere ermöglicht IInspectable.GetRuntimeClassName den Client eines Objekts, einen WinRT-Typnamen abzurufen, der in Metadaten aufgelöst werden kann, um die Sprachprojektion zu ermöglichen.

Schnittstelle erfordert

Wie oben erwähnt, kann eine Schnittstelle angeben, dass eine oder mehrere andere Schnittstellen erforderlich sind, die für jedes Objekt implementiert werden müssen, das die betreffende Schnittstelle implementiert. Wenn iButton beispielsweise IControl erfordert, muss jede Klasse, die IButton implementiert, auch IControl implementieren.

Aber weder das WinRT-Typsystem noch das ABI hat ein Konzept der Schnittstellenvererbung. So hat die Idee, neue Funktionen hinzuzufügen, indem neue Schnittstellen implementiert werden, die von vorhandenen Schnittstellen erben (z. B. IFoo2 erbt von IFoo) keine Bedeutung. Es ist wahr, dass eine WinRT-Sprachprojektion eine Vererbungsbeziehung für die Einfache Nutzung in dieser bestimmten Sprache verwenden kann, und eine Laufzeitklasse kann Vererbung verwenden, aber die Schnittstellenvererbung ist im Kontext von MIDL 3.0-Dokumenterstellung nicht vorhanden (siehe MIDL 3.0-Schnittstellen).

Parametrisierte Schnittstellen

Schnittstellen unterstützen die Typparameterisierung. Eine parametrisierte Schnittstellendefinition gibt zusätzlich zur Liste der Schnittstellenelemente und erforderlichen Schnittstellen eine Typparameterliste an. Eine erforderliche Schnittstelle einer parametrisierten Schnittstelle kann dieselbe Typargumentliste verwenden, sodass ein einzelnes Typargument verwendet wird, um die parametrisierte Instanz der Schnittstelle und der benötigten Schnittstelle anzugeben (z IVector<T> requires IIterable<T>. B. ). Die Signatur eines Elements (also Methode, Eigenschaft oder Ereignis) einer parametrisierten Schnittstelle kann auf einen Typ aus der Typargumentliste der parametrisierten Schnittstelle verweisen (z IVector<T>.SetAt([in] UInt32 index, [in] T value). B. ).

Drittanbieter können keine neuen parametrisierten Schnittstellen definieren. Nur die vom System definierten parametrisierten Schnittstellen werden unterstützt.

Delegaten

Eine Stellvertretung ist ein WinRT-Typ, der als typsicherer Funktionszeiger fungiert. Eine Stellvertretung ist im Wesentlichen ein einfaches WinRT-Objekt, das eine einzelne Schnittstelle verfügbar macht, die von IUnknown erbt, und definiert eine einzelne Methode namens Invoke. Wenn Sie die Stellvertretung aufrufen, wird wiederum die Methode aufgerufen, auf die sie verweist. Stellvertretungen werden häufig (aber nicht ausschließlich) zum Definieren von WinRT-Ereignissen verwendet.

Eine WinRT-Stellvertretung ist ein benannter Typ und definiert eine Methodensignatur. Delegate-Methodensignaturen entsprechen den gleichen Regeln für Parameter wie Schnittstellenmethoden. Die Signatur- und Parameternamen der Invoke-Methode müssen der Definition des Delegaten entsprechen.

Wie Schnittstellen müssen nicht parametrisierte Stellvertretungen über eine eindeutige Schnittstellen-ID (aka IID) verfügen, die über ein GuidAttribute angegeben wird. Die IID des Delegaten wird als IID der einzelnen Methodenschnittstelle verwendet, die zum Implementieren des Delegaten verwendet wird. Parametrisierte Stellvertretungen müssen eine eindeutige parametrisierte Schnittstellen-ID (auch als PIID bezeichnet) aufweisen, die über eine GuidAttribute angegeben wird. Die PIID wird verwendet, um eine IID für eine bestimmte parametrisierte Delegateninstanz über den oben angegebenen Algorithmus zu generieren.

Eine Stellvertretung muss über öffentliche Sichtbarkeit verfügen.

IUnknown

Beachten Sie, dass Stellvertretungen im Gegensatz zu WinRT-Schnittstellen IUnknown implementieren, aber nicht IInspectable. Dies bedeutet, dass sie zur Laufzeit nicht auf Typinformationen überprüft werden können.

Parametrisierte Delegaten

Delegaten unterstützen die Typparameterisierung. Eine parametrisierte Delegatendefinition gibt zusätzlich zur herkömmlichen Methodensignatur wie oben angegeben eine Typparameterliste an. In der Methodensignatur kann jeder Parameter als einer der Typen aus der Liste der parameterisierten Delegatentypargumente angegeben werden.

Drittanbieter können keine neuen parametrisierten Stellvertretungen definieren. Nur die vom System definierten parametrisierten Stellvertretungen werden unterstützt.

Interface members (Schnittstellenmember)

WinRT-Schnittstellen unterstützen drei Arten von Membern: Methoden, Eigenschaften und Ereignisse. Schnittstellen verfügen möglicherweise nicht über Datenfelder.

Methoden

WinRT-Schnittstellen unterstützen Methoden, die null oder mehr Parameter übernehmen und ein HRESULT zurückgeben, das den Erfolg oder Fehler des Methodenaufrufs angibt. Eine Methode kann optional einen einzelnen Out-Parameter angeben, der als Rückgabewert in Ausnahmesprachen projiziert werden soll. Dieser Rückgabewert-Wert muss, falls angegeben, der letzte Parameter in der Methodensignatur sein.

Eine Methode muss über öffentliche Sichtbarkeit verfügen.

Eine Methode verwendet möglicherweise keine variablen Anzahl von Argumenten. Eine Methode verfügt möglicherweise nicht über optionale Parameter oder Parameter mit Standardwerten.

Eine Methode kann nicht parametrisiert werden. Parameterisierte Delegaten und Methoden von parametrisierten Schnittstellen können Typparameter des enthaltenen Typs in der Methodensignatur verwenden.

Parameter

Alle Methodenparameter mit Ausnahme von Arraylängenparametern (unten beschrieben) müssen einen Namen und einen Typ aufweisen. Beachten Sie, dass Rückgabewerte einen Namen wie Parameter angeben müssen. Methodenparameternamen, einschließlich des Rückgabetypnamens, müssen innerhalb des Bereichs der Methode eindeutig sein.

Nur Parameter für parametrisierte Stellvertretungen und Member parametrisierter Schnittstellen können einen parametrisierten Typ für den Parametertyp angeben. Methoden werden möglicherweise nicht einzeln parametrisiert. Parameter können immer parameterisierte Typinstanzen (z. B IVector<int>. ) als Parametertyp angeben.

Alle Methodenparameter müssen ausschließlich in oder out-Parametern vorhanden sein. Ein-/Aus-Parameter werden nicht unterstützt.

Während eine Methode auf einer WinRT-Schnittstelle ein HRESULT zurückgeben muss, kann eine Methode optional angeben, dass der endgültige Out-Parameter als Rückgabewert verwendet werden soll, wenn die Methode in Ausnahmesprachen projiziert wird. Solche Parameter werden als [out, retval]-Parameter bezeichnet, nachdem die MIDL-Syntax verwendet wurde, um sie zu deklarieren. Wenn ein [out, retval]-Parameter angegeben wird, muss es sich um den letzten Parameter in der Methodensignatur handelt.

Außer [out, retval] muss am Ende der Parameterliste angezeigt werden, gibt es keine anderen Sortieranforderungen für out-Parameter.

Arrayparameter

WinRT-Methoden unterstützen konforme Arrayparameter. Arrays können niemals verwendet werden, außer als Parameter. Sie können nicht eigenständige benannte Typen sein, und sie können nicht als Strukturfeldtyp verwendet werden. Arrayparameter können als in, outund retval Parameter verwendet werden.

WinRT unterstützt Arrayparameter der meisten WinRT-Typen, einschließlich grundlegender Typen (einschließlich Zeichenfolge und GUID), Strukturen, Enumerationen, Delegaten, Schnittstellen und Laufzeitklassen. Arrays anderer Arrays sind nicht zulässig.

Da sie konform sind, müssen Arrayparameter immer unmittelbar in der Parameterliste durch einen Parameter für die Arraygröße vorangestellt werden. Der Parameter für die Arraygröße muss ein UInt32 sein. Der Parameter für die Arraygröße weist keinen Namen auf.

WinRT unterstützt drei verschiedene Arrayübergabestile.

  • PassArray. Diese Formatvorlage wird verwendet, wenn der Aufrufer eine Matrix für die Methode bereitstellt. In dieser Formatvorlage sind sowohl der Parameter für die Arraygröße als auch der Arrayparameter beide in Parameter.
  • FillArray. Diese Formatvorlage wird verwendet, wenn der Aufrufer ein Array für die zu füllende Methode bereitstellt, bis zu einer maximalen Arraygröße. In dieser Formatvorlage ist der Parameter für die Arraygröße ein in Parameter, während der Arrayparameter ein out Parameter ist. Bei Verwendung der FillArray-Formatvorlage kann der Arrayparameter optional einen der anderen Parameter als Arraylängenparameter angeben. Details finden Sie im Folgenden.
  • ReceiveArray. Diese Formatvorlage wird verwendet, wenn der Aufrufer ein Array empfängt, das von der Methode zugewiesen wurde. In dieser Formatvorlage sind der Parameter für die Arraygröße und der Arrayparameter beide out Parameter. Darüber hinaus wird der Arrayparameter nach Bezug übergeben (d. b. ArrayType**, anstatt ArrayType*).

Hinweis

Die Kombination eines out Arraygrößesparameters, aber ein in Arrayparameter ist in WinRT nicht gültig.

Wenn ein Arrayparameter als [out, retval]-Parameter verwendet wird, muss der Parameter für die Arraylänge ein out Parameter sein, d. h. nur die ReceiveArray-Formatvorlage ist für Arrays zulässig retval .

Arraylängenparameter

Ein Arrayparameter des FillArray-Stils kann optional einen anderen Parameter als Arraylängenparameter angeben. Wenn der erforderliche Arraygrößenparameter die maximale Anzahl von Elementen in einem Array angibt, das vom Aufrufer bereitgestellt wird, gibt der Parameter für die Arraylänge die Anzahl der Elemente an, die tatsächlich vom angerufenen Element ausgefüllt wurden.

Der Parameter für die Arraylänge wird mit dem LengthIs-Attribut für den Arrayparameter angegeben.

Methodenüberladung

Im Bereich einer einzelnen Schnittstelle kann mehrere Methoden denselben Namen haben. Methoden mit demselben Namen auf einer Schnittstelle müssen eindeutige Signaturen aufweisen. Eigenschaften und Ereignisse können nicht überladen werden.

WinRT unterstützt überladene Parametertypen, bevorzugt jedoch die Überladung für die Anzahl der Eingabeparameter – auch bekannt als die Arität der Methode. Dies geschieht, um dynamische, schwach typierte Sprachen (z. B. JavaScript) zu unterstützen.

Wenn eine Schnittstelle mehrere Methoden mit demselben Namen und der Anzahl der Eingabeparameter enthält, müssen genau eine dieser Methoden als Standard gekennzeichnet werden. Von allen überladenen Methoden mit demselben Namen und der Anzahl der Eingabeparameter wird nur die als Standard gekennzeichnete Methode von einer dynamischen, schwach typierten Sprache projiziert. Wenn nur eine einzelne überladene Methode eines angegebenen Namens und der Anzahl der Eingabeparameter vorhanden ist, ist die Markierung als Standard gültig, aber nicht erforderlich.

Für die Bestimmung der Arität einer Methode werden Arrayparameter und deren erforderliche Längenparameter als einzelner Parameter betrachtet. Die PassArray- und FillArray-Formatvorlagen werden als ein einzelner Eingabeparameter betrachtet, während die EmpfangenArray-Formatvorlage als einzelner Ausgabeparameter betrachtet wird.

Wenn mehrere Methoden auf einer Schnittstelle denselben Namen haben, muss ein eindeutiger Name für jede kollidierende Methode in einem OverloadAttribute gespeichert werden, das der Methode zugeordnet ist. Standardmäßig überladene Methoden tragen das DefaultOverloadAttribute.

Überladen von Operatoren

WinRT unterstützt keine Operatorüberladung. Methoden dürfen nicht mit den speziellen Operatornamen wie op_Addition benannt werden, die in der ECMA 335 CLI-Spezifikation, Partition I, Abschnitt 10.3 angegeben sind.

Eigenschaften

Eine Eigenschaft ist ein Paar von Get/Set-Methoden mit übereinstimmendem Namen und Typ, die in einigen Sprachprojektionen anstelle von Methoden angezeigt werden.

Eine Eigenschaft und ihre get/set-Methoden müssen öffentliche Sichtbarkeit haben.

Eine Eigenschaft muss über eine get Methode verfügen. Eine Eigenschaft getter-Methode verfügt über keine Parameter und gibt einen Wert des Eigenschaftentyps zurück. Eine Eigenschaft mit nur einer get Methode wird als schreibgeschützte Eigenschaft bezeichnet.

Eine Eigenschaft kann optional über eine set Methode verfügen. Eine Eigenschaftssatzmethode weist einen einzelnen Parameter des Eigenschaftentyps auf und gibt void zurück. Eine Eigenschaft mit einer get und einer set Methode wird als Lese-/Schreibeigenschaft bezeichnet.

Eigenschaften werden möglicherweise nicht parametrisiert. Eigenschaften aus parametrisierten Schnittstellen können Typparameter des enthaltenden Typs als Eigenschaftstyp verwenden.

Ereignisse

Ein Ereignis ist ein Paar von Add/Remove-Listenermethoden mit übereinstimmendem Namen und Stellvertretungstyp. Ereignisse sind ein Mechanismus für die Schnittstelle, um interessierte Parteien zu benachrichtigen, wenn etwas von Bedeutung geschieht.

Ein Ereignis und seine Add/Remove-Listenermethoden müssen öffentliche Sichtbarkeit aufweisen.

Eine Ereignislistenermethode add verfügt über einen einzelnen Parameter des Ereignisstellvertretungstyps und gibt einen Windows zurück. Foundation.EventRegistrationToken. Eine Ereignislistenermethode remove verfügt über einen einzelnen Parameter des Windows. Foundation.EventRegistrationToken type, and returns void.

Ereignisse werden möglicherweise nicht parametrisiert. Ereignisse aus parametrisierten Schnittstellen können Typparameter des enthaltenden Typs als Ereignisstellvertretungstyp verwenden.

Laufzeitklassen

Mit WinRT können Sie eine Klasse definieren. Eine Klasse muss eine oder mehrere Schnittstellen implementieren. Eine Klasse kann keine Typmember direkt implementieren (das heißt, es kann keine eigenen Methoden, Eigenschaften oder Ereignisse definieren). Eine Klasse muss eine Implementierung aller Elemente aller implementierten Schnittstellen bereitstellen.

Es gibt verschiedene Arten von Schnittstellen, die unten ausführlich beschrieben werden.

  • Memberschnittstellen (einschließlich geschützter und überschriebener Schnittstellen)
  • Statische Schnittstellen
  • Aktivierungs-Factoryschnittstellen
  • Kompositions-Factoryschnittstellen

Laufzeitklassen können nicht parametrisiert werden. Eine Laufzeitklasse kann eine parametrisierte Schnittstelleninstanz (d. h. eine parametrisierte Schnittstelle mit allen angegebenen Typparametern) implementieren, an einer beliebigen Stelle, an der sie normalerweise eine nicht parametrisierte Schnittstelle akzeptiert.

Eine Laufzeitklasse muss über öffentliche Sichtbarkeit verfügen.

Eine Laufzeitklasse kann nur Schnittstellen implementieren, die nicht exklusiv sind (also nicht das exclusiveTo-Attribut tragen) oder die ausschließlich für die betreffende Laufzeitklasse sind. Eine Laufzeitklasse implementiert möglicherweise keine Schnittstellen, die exklusiv für eine andere Laufzeitklasse sind. Es gibt eine Ausnahme für diese Regel– eine durchkomposierbare Klasse kann Schnittstellen implementieren, die ausschließlich für eine Klasse in ihrer Ableitungskette gelten, die als überschrieben werden kann. Details zu außerkraftsetzenden Schnittstellen, denen sie folgen sollen.

Memberschnittstelle

Eine Laufzeitklasse kann null oder mehr Memberschnittstellen implementieren. Memberschnittstellen ermöglichen Es Klassen, Funktionen verfügbar zu machen, die Instanzen der Klasse zugeordnet sind. Eine Laufzeitklasse gibt eine Liste der von ihr implementierten Memberschnittstellen an. Einträge in der Liste der von einer Laufzeitklasse implementierten Memberschnittstellen können optional Versionsinformationen enthalten. Details zur zu folgenden Laufzeitklassenversionsverwaltung.

Memberschnittstellen werden direkt auf Instanzen der Laufzeitklasse implementiert.

Laufzeitklassen, die eine oder mehrere Memberschnittstellen implementieren, müssen eine der Memberschnittstellen als Standardschnittstelle angeben. Laufzeitklassen, die null Memberschnittstellen implementieren, geben keine Standardschnittstelle an.

Statische Schnittstellen

WinRT-Klassen können null oder mehr statische Schnittstellen angeben. Statische Schnittstellen ermöglichen Es Klassen, Funktionen verfügbar zu machen, die der Klasse selbst zugeordnet sind, anstatt mit bestimmten Instanzen der Klasse.

Eine Klasse muss mindestens ein Element oder eine statische Schnittstelle angeben. Eine Klasse ohne Member und keine statischen Schnittstellen sind ungültig.

Statische Schnittstellen werden über ein StaticAttribute angegeben, das der Laufzeitklasse zugeordnet ist. StaticAttribute enthält einen Verweis auf die statische Schnittstellenreferenz sowie Versionsinformationen. Details zur zu folgenden Laufzeitklassenversionsverwaltung.

Während statische Schnittstellen als Teil der Laufzeitklasse deklariert werden, werden sie tatsächlich nicht in Klasseninstanzen selbst implementiert. Stattdessen werden sie auf der Aktivierungsfabrik der Klasse implementiert. Details zu Aktivierungsfabriken, denen sie folgen sollen.

Aktivierung

Laufzeitklassen unterstützen optional die Aktivierung – die Möglichkeit des Systems, Instanzen einer angegebenen Klasse zu erzeugen. Klassen müssen mindestens eine Memberschnittstelle implementieren, um die Aktivierung zu unterstützen.

WinRT definiert drei Aktivierungsmechanismen: direkte Aktivierung (ohne Konstruktorparameter), Factoryaktivierung (mit mindestens einem Konstruktorparameter) und Kompositionsaktivierung. Nicht komponierbare Klassen können entweder direkte und/oder factoryaktivierung unterstützen. Composable-Klassen unterstützen nur die composable Aktivierung. Details zur kompositions- und komponierbaren Aktivierung folgen.

Klassen, die die direkte Aktivierung unterstützen, werden durch Aufrufen der IActivationFactory.ActivateInstance-Methode auf der Aktivierungsfabrik der Klasse aktiviert. Diese Methode verwendet keine Parameter und gibt eine neu aktivierte Instanz der Laufzeitklasse zurück. Details zu Aktivierungsfabriken, denen sie folgen sollen.

Klassen, die die Factoryaktivierung unterstützen, definieren eine oder mehrere Factoryschnittstellen, die wiederum eine oder mehrere Factorymethoden definieren. Diese Factoryschnittstellen werden auf der Aktivierungsfabrik der Klasse implementiert.

Factorymethoden verwenden einen oder mehrere in Parameter und müssen eine neu aktivierte Instanz der Laufzeitklasse zurückgeben. Andere out Parameter, die über die neu aktivierte Klasseninstanz hinausgehen, sind nicht zulässig. Factorymethoden müssen mindestens einen Parameter verwenden– die parameterlose Factoryaktivierung ist nicht zulässig. Die direkte Aktivierung muss für die parameterlose Aktivierung verwendet werden.

Klassen, die die direkte oder factoryaktivierung unterstützen, werden mit "ActivatableAttribute" gekennzeichnet. Das AktivableAttribute enthält Versionsinformationen (Details zur zu folgenden Laufzeitklassenversion) sowie einen optionalen Verweis auf die Factoryschnittstelle. Klassen können mit mehreren aktivierbarenAttributen gekennzeichnet werden– mindestens eine für die Standardaktivierung sowie eine für jede Factoryschnittstelle, die von der Aktivierungsfabrik der Klasse implementiert wird. Klassen, die mit "ActivatableAttribute" gekennzeichnet sind, werden möglicherweise auch nicht mit dem ComposableAttribute gekennzeichnet. Details zur Komposition, die folgen sollen.

Zusammensetzung

Laufzeitklassen unterstützen optional die Komposition – die Möglichkeit, dass mehrere Klasseninstanzen kombiniert werden können, was als ein einzelnes Objekt von außen erscheint. WinRT verwendet Komposition als Form der Vererbung der Laufzeitklasse.

WinRT-Klassen können optional eine einzelne komponierbare Basisklasse verfassen, die wiederum eine einzelne verfassende Basisklasse usw. verfassen kann. Eine Klasse muss nicht selbst komponierbar sein, um eine verfassende Basisklasse zu erstellen. Klassen können nur mit einer komponierbaren Klasse als Basisklasse verfassen. Eine verfassenbare Klasse ist nicht erforderlich, um eine andere verfassende Klasse zu verfassen (das heißt, es kann der Stamm der Hierarchie sein). Zirkeldiagramme der Komposition (z. B. A verfassen B, die A verfassen) sind nicht zulässig.

Zur Laufzeit ist eine Komponierungsklasse eine Aggregation von WinRT-Objekten – eine für jedes Objekt in der Kompositionskette. Diese aggregierten Objekte delegieren die Identität und Lebensdauer des ursprünglich aktivierten Objekts in der Kompositionskette (sogenanntes Steuerungsobjekt). Jedes Objekt in der Kette enthält einen nicht delegierenden IInspectable-Zeiger an die Klasse, die er erstellt, um Methoden für zusammengesetzte Basisklassenschnittstellen aufzurufen, einschließlich Methoden für geschützte Schnittstellen. Jedes Objekt in der Kette weist einen Zeiger auf die Steuerungsklasse zum Delegieren der Lebensdauer und Identität sowie zum Aufrufen von Methoden für überschriebene Schnittstellen auf. Details zu geschützten und außerkraftsetzenden Schnittstellen, denen sie folgen sollen.

Nehmen wir uns das Beispiel an, in dem Schaltflächensteuerelement erstellt wird, was wiederum UIElement erstellt. In diesem Beispiel aggregiert eine Instanz von Button eine Steuerelementinstanz , die wiederum eine UIElement-Instanz aggregiert. Alle drei Objekte weisen einen Verweis auf das Button-Objekt zum Steuern der Lebensdauer und Identität sowie zum Abfragen überschriebener Schnittstellen auf. Jedes Objekt verfügt über einen IInspectable-Zeiger auf das Objekt, das er erstellt (Button hält einen Zeiger auf Control; Steuerelement enthält einen Zeiger auf UIElement), um Methoden für Schnittstellen aufrufen zu können, die in zusammengesetzten Klassen implementiert sind, einschließlich geschützter Schnittstellen.

Eine Klasse kann keine Schnittstellen implementieren, die für die klasse definiert sind, die sie verfasst, oder keine Klasse in der Kompositionskette, es sei denn, die Schnittstelle ist in der verfassenden Klasse als überschreibend gekennzeichnet. Details zu außerkraftsetzenden Schnittstellen, denen sie folgen sollen.

Eine verfassenbare Klasse muss mit einem oder mehreren ComposableAttributes gekennzeichnet werden. Das ComposableAttribute trägt einen Verweis auf die Kompositionsfabrikschnittstelle – ob die Factorymethoden auf der Kompositionsfabrikschnittstelle zum Steuern der Objektaktivierung oder nicht verwendet werden können – sowie Versionsinformationen. Details zu Kompositions-Factory-Schnittstellen und Versionsverwaltungen, denen sie folgen sollen. Eine Klasse kann mit mehreren ComposableAttributes gekennzeichnet werden – eine für jede Kompositionsfabrikschnittstelle, die von der Aktivierungsfabrik der Klasse implementiert wird.

Die JavaScript-Sprachprojektion unterstützt keine Klassenkomposition. Daher sollten verfassende Klassen und Klassen, die komponierbare Klassen verfassen, mit dem WebHostHiddenAttribute gekennzeichnet werden, das angibt, dass JavaScript nicht versuchen sollte, diese Typen zu projizieren.

Drittanbieter können nur Klassen definieren, die andere verfassende Klassen erstellen. Möglicherweise definieren Sie ihre eigene komponierbare Stammklasse nicht.

Verfassenfähige Aktivierung

Eine komponierbare Klasse muss eine oder mehrere Kompositionsfabrikschnittstellen definieren, die wiederum eine oder mehrere Kompositionsfabrikmethoden implementieren. Kompositions-Factoryschnittstellen werden auf der Aktivierungsfabrik der Klasse implementiert. Details zu Aktivierungsfabriken, denen sie folgen sollen.

Eine Kompositionsfabrikschnittstelle wird verwendet, um komponierbare Instanzen der Klasse zu erstellen. Eine komponierbare Factoryschnittstelle deklariert null oder mehr komponierbare Factorymethoden, die verwendet werden können, um Instanzen der Klasse für Kompositionszwecke zu aktivieren. Beachten Sie, dass es legal ist, eine komponierbare Fabrikschnittstelle mit Null-Factory-Methoden zu haben. Dies bedeutet, dass die Klasse für die Komposition verwendet werden kann, aber dass Drittanbieter die Klasse möglicherweise nicht direkt verfassen – die Methoden zum Erstellen von Instanzen sind nur intern.

Eine verfassenbare Klasse deklariert, ob die Factorymethoden auf einer bestimmten Kompositionsfabrikschnittstelle verwendet werden können, um die Klasse direkt als Steuerelementobjekt zu aktivieren oder nicht. Composable Factory-Schnittstellen, die als öffentlich gekennzeichnet sind, können verwendet werden, um eine Klasse direkt als steuerungsfähiges Objekt zu aktivieren, sowie indirekt, um eine Klasse als zusammengesetztes Objekt zu aktivieren. Durch trennbare Werksschnittstellen, die als geschützt gekennzeichnet sind, kann nur verwendet werden, um eine Klasse indirekt als zusammengesetztes Objekt zu aktivieren. Komponierbare Klassen können immer als zusammengesetzte Objekte aktiviert werden.

Eine Kompositionsfabrikschnittstelle muss die Laufzeitklasse sein exclusiveto , von der sie implementiert wird.

Wie eine Aktivierungsfabrikmethode muss eine Kompositionsfabrikmethode eine Instanz der komponierbaren Klasse zurückgeben. Darüber hinaus verfügt eine Kompositionsfabrikmethode über zwei zusätzliche Parameter: den steuernden Parameter IInspectable* [in] und den nicht delegierenden IInspectable** [out]-Parameter. Eine Kompositionsfabrikmethode kann optional zusätzliche in Parameter aufweisen. Wenn angegeben, müssen die zusätzlichen Parameter am Anfang der Methodensignatur vor den zuvor aufgeführten mandatierten Parametern auftreten. Eine Kompositionsfabrikmethode verfügt möglicherweise nicht über zusätzliche out Parameter, die nicht delegieren IInspectable** und die Rückgabewertparameter hinausgehen.

Wenn eine komponierbare Klasse für die Komposition aktiviert wird (z. B. Steuerelement oder UIElement , wenn eine Schaltflächeninstanz aktiviert wird), wird ein Zeiger auf das Objekt übergeben, das die Identität und Lebensdauer steuert, über den Steuerelement-IInspectable * [in]-Parameter übergeben. Die composable Factory-Methode gibt die neu aktivierte Instanz als Rückgabewert zurück. Diese Instanz delegiert alle Identitäts- und Lebensdauerverwaltungsfunktionen an das steuernde IInspectable* , das bereitgestellt wurde. Darüber hinaus gibt die composable Factory-Methode einen Zeiger auf ein nicht delegierendes IInspectable* zurück, mit dem die verfassende Klasse Methoden für eine zusammengesetzte Klasse aufrufen kann.

Wenn eine komponierbare Klasse als Steuerelementklasse aktiviert wird (z. B. Button im vorherigen Beispiel), werden die gleichen composable Factory-Methoden wie für die Aktivierung für die Komposition verwendet. Beim direkten Aktivieren einer komponierbaren Klasse wird null für den steuernden *IInspectable* -Parameter übergeben. Dies ist ein Indikator für die komponierbare Klasse, die als Steuerungsklasse aktiviert wird. Wenn eine Steuerungsklasse die Instanz der von ihr verfassten Klasse erstellt, übergibt sie einen Verweis auf sich selbst als steuernden IInspectable* -Parameter. Die composable Factory-Methode gibt die steuernde Klasseninstanz als Rückgabewert zurück. Der nicht delegierende IInspectable** [out]-Parameter wird vom Clientcode ignoriert, wenn eine steuerungskomposierbare Klasse aktiviert wird.

Die Schaltflächenklasse, die auf dem früheren Button -Control ->>UIElement-Beispiel basiert, wird aktiviert, indem eine der Kompositionsfabrikmethoden aufgerufen und Null für den äußeren Parameter übergeben wird. Schaltfläche würde wiederum eine Steuerelementinstanz aktivieren und einen Verweis als äußerer Parameter an sich selbst übergeben. Das Steuerelement aktiviert wiederum eine UIElement-Instanz , wobei der äußere Verweis als äußerer Parameter übergeben wird. Die UIElement-Factorymethode würde zum Steuerelement des neu erstellten UIElement im Instanzparameter sowie einen Verweis auf das nicht delegierende IInspectable des UIElements im inneren Parameter zurückgeben. Die Control Factory-Methode würde zurück zur Schaltfläche des neu erstellten Steuerelements im Instanzparameter sowie einen Verweis auf das nicht delegierende IInspectable des Steuerelements im inneren Parameter zurückgeben. Die Schaltflächenkompositions-Factory würde zum aufrufenden Code der neu erstellten Schaltfläche im Instanzparameter und null für den inneren Parameter zurückkehren.

Es ist möglich, dass eine Klasse manchmal für Komposition aktiviert und andere Zeiten als Kontrollklasse aktiviert wird. Wenn beispielsweise RadioButton zusammengesetzte Schaltfläche aktiviert wurde, wird "Button" für die Komposition aktiviert, wenn ein RadioButton aktiviert wurde; aber als Steuerungsklasse aktiviert, wenn Schaltfläche direkt aktiviert wurde. In beiden Fällen würde die Steuerelementklasse , die Button verfasst, für die Komposition aktiviert werden.

Geschützte Schnittstellen

Eine komponierbare Klasse kann null oder mehr seiner Memberschnittstellen deklarieren, um geschützt zu werden. Eine nicht composierbare Klasse deklariert möglicherweise keine Memberschnittstellen, die geschützt werden sollen. Nur Code in einer Klasse, die eine verfassende Klasse erstellt (direkt oder indirekt), kann Schnittstellen abfragen und verwenden, die von der composable-Klasse als geschützt deklariert werden. Code von außerhalb der Kompositionskette kann keine Abfragen nach, oder verwenden Schnittstellen, die von der composable-Klasse als geschützt deklariert werden.

Wenn UIElement z. B. eine geschützte Schnittstelle IUIElementProtected deklariert, können nur Klassen, die UIElement verfassen , einschließlich direkter (Steuerelement) und indirekter (Button)-Komposition, die IUIElementProtected-Schnittstelle abfragen und verwenden.

Außerkraftsetzungsschnittstellen

Eine komponierbare Klasse kann null oder mehr seiner Memberschnittstellen deklarieren, um außer Kraft zu setzen. Eine außerkraftbare Schnittstelle kann nur abgefragt und innerhalb einer Kompositionskette verwendet werden– ähnlich wie die Regeln zum Zugriff auf geschützte Schnittstellen, die zuvor beschrieben wurden. Wenn jedoch eine geschützte Schnittstelle nur von der Klasse implementiert werden kann, die sie ursprünglich deklariert hat, können überschriebene Schnittstellen durch Klassen erneut implementiert werden, die die Klasse verfassen, die die überschreibbare Schnittstelle implementiert hat.

Zur Laufzeit müssen alle composablen Klassencode, der die überschriebene Schnittstelle nutzt, QueryInterface für die Schnittstelle über den steuernden IInspectable* -Zeiger abfragen, der für die Identitäts- und Lebensdauerdelegierung verwendet wird. Dieser Zeiger gibt die Implementierung der außerkraftbaren Schnittstelle frühestens in der Kompositionskette zurück (das heißt, am nächsten an die steuernde Klasseninstanz). Eine Klasse, die auf die überschreibbaren Schnittstellen der klasse zugreifen möchte, die er verfasst, kann dies über den nicht delegierenden Verweis tun, den eine durchkomponierbare Klasse an seine zusammengesetzte Klasse hält.

Nehmen wir uns das Beispiel an, in dem UIElement eine überschreibbare Schnittstelle IUIElementOverridable deklariert. In diesem Fall können Klassen, die von UIElement abgeleitet werden, einschließlich direkter (Steuerelement) und indirekter (Button)-Ableitung, diese implementieren. Wenn Code in UIElement erforderlich ist, um auf Funktionen in IUIElementOverridable zuzugreifen, würde UIElement das Steuern von IInspectable abfragen, um die früheste Implementierung in der Kompositionskette abzurufen. Wenn sowohl Steuerelement als auch SchaltflächeIUIElementOverridable implementiert wurden, wird die Schaltflächenimplementierung zurückgegeben, wenn das Steuern von IInspectable abgefragt wurde. Wenn Button auf seine zusammengesetzte Klassenfunktionalität zugreifen möchte, kann er die nicht delegierende IInspectable verwenden, die von der Kompositionsfabrikmethode zurückgegeben wurde, um die Basisklasse für diese Schnittstelle abzufragen.

Aktivierungsfactorys

Optional verfügt eine Laufzeitklasse über eine Aktivierungsfabrik. Eine Laufzeitklasse muss über eine Aktivierungsfabrik verfügen, wenn die Klasse aktivierbar, verfassend oder über statische Schnittstellen verfügt. Die Aktivierungsfabrik für eine Klasse kann zur Laufzeit über die RoGetActivationFactory Win32-Funktion aus dem System abgerufen werden.

Aktivierungsfabriken müssen die IActivationFactory-Schnittstelle implementieren. Allerdings bieten nur Klassen, die die direkte Aktivierung unterstützen, eine Implementierung der einzelnen IActivationFactory-MethodeActivateInstance. Klassen, die die direkte Aktivierung nicht unterstützen, müssen E_NOTIMPL von IActivationFactory.ActivateInstance zurückgeben.

Die Aktivierungsfabrik muss alle Aktivierungsfabrikschnittstellen, Kompositionsfabrikschnittstellen und statische Schnittstellen implementieren, die in der Laufzeitklasse definiert sind.

Es gibt keine Garantie, dass Sprachprojektionen eine einzelne Aktivierungsfabrikinstanz für die Lebensdauer der Fabrik beibehalten. WinRT-Klassenautoren, die langlebige Informationen für statischen Memberzugriff speichern müssen, müssen sie irgendwo außerhalb der Aktivierungsfabrik speichern.

Klassenbasierte Projektion

Während WinRT in erster Linie ein schnittstellenbasiertes Programmiermodell unter der Haube ist, bieten Laufzeitklassen ein klassenbasiertes Programmiermodell, das besser an moderne, mainstream-, objektorientierte (OO)-Programmiersprachen ausgerichtet ist. Sprachprojektionen werden erwartet, eine Laufzeitklasse als einzelne Entität zu projizieren, anstatt als eine Tüte von Schnittstellen, die der Entwickler separat behandeln muss.

Um dieses klassenbasierte Modell zu erreichen, werden Sprachprojektionen für Projekttypmitglieder aus den Memberschnittstellen einer Klasse als direkte Klassenmitglieder erwartet. Sprachprojektionen werden erwartet, dass Elemente des Typs von Elementen aus den statischen Schnittstellen einer Klasse als statische Klassenmember projiziert werden. Schließlich wird erwartet, dass Sprachprojektionen Projektaktivierungsmethoden (direkte Aktivierung sowie Schnittstellen von Factory- und composable Factory-Schnittstellen) als Klassenkonstruktoren projektieren.

Um diese klassenbasierte Projektion zu unterstützen, geben Metadaten für Laufzeitklassen ein Klassenelement für alle Methoden, Eigenschaften und Ereignisse aus jeder von ihnen implementierten Schnittstelle an. Jedes Klassenelement ist explizit an das Schnittstellenelement gebunden, in dem es ursprünglich definiert wurde. Auf diese Weise können Sprachprojektionen die Klasse als einzelne Entität verfügbar machen, wobei alle Schnittstellenabfragen und -referenzzählungen im Auftrag des Entwicklers behandelt werden.

Standardmäßig wird jedes implementierte Schnittstellenmitglied als Klassenmitglied projiziert. Da Laufzeitklassen jedoch mehrere unabhängige Schnittstellen und Versionen im Laufe der Zeit implementieren können (Versionsverwaltungsdetails folgen), ist es möglich, dass Namenkonflikte für Elemente vorhanden sind, die von einer einzelnen Laufzeitklasse implementiert werden.

Wenn Kollisionen auftreten, ist die Standard-Klassenelement-Projektion unmöglich. Wenn Konflikte über Schnittstellen hinweg auftreten, die in separaten Versionen hinzugefügt wurden, wird das kollidierende Element aus der frühesten Version als Klassenmitglied projiziert. Wenn Kollisionen über Schnittstellen hinweg auftreten, die in derselben Version hinzugefügt wurden, werden keine der kollidierenden Member als Klassenmitglieder projiziert. Beachten Sie, dass Methoden mit kollidierenden Namen zulässig sind, solange alle Versionen unterschiedlicher Arität sind, wie in der Methodenüberladung beschrieben.

Schnittstellenmitglieder, die nicht als Klassenmitglieder projiziert werden, müssen Entwicklern zur Verfügung gestellt werden. Dies geschieht in der Regel durch einen Umwandlungs- oder dynamischen Nachschlageoperator, sodass der Entwickler die spezifische Schnittstelle und Methode angeben kann, die sie aufrufen möchten.

Um Methodennamenkonflikte aufzulösen, können Laufzeitklassen alternative Namen für Methoden für das Element und statische Schnittstellen angeben, die sie implementieren. Dieser alternative Name wird von der Sprachprojektion verwendet, um einen eindeutigen Zugriff auf spaltende Methodennamen aus einer Klasseninstanz bereitzustellen. Die Laufzeitklasse kann zwar einen alternativen Methodennamen bereitstellen, die Methodensignatur, Parameter und alle Attribute, die der Methode zugeordnet sind, oder ihre Attribute müssen jedoch genau mit der ursprünglichen Schnittstellendefinition übereinstimmen.

Da direkte Aktivierung, Factorymethoden und Kompositionsfabrikmethoden als Klassenkonstruktoren projiziert werden, werden sie alle auf der Laufzeitklasse projiziert, als ob sie denselben Namen haben. Alle Methoden über alle Factoryschnittstellen hinweg müssen eindeutige Signaturen aufweisen, die aritybasierte Überladung über typbasierte Überladungen bevorzugen und die DefaultOverloadAttribute verwenden, um Fabrikmethoden derselben Arität zu disambiguieren.

Klassenversionsverwaltung

Laufzeitklassen sind additiv versionierbar. Nachfolgende Versionen einer bestimmten Laufzeitklasse können zusätzliche Schnittstellen aller Typen angeben, mit weiteren Details zu einzelnen Schnittstellentypen unten. Vorhandene Schnittstellen, die von einer Klasse angegeben sind, werden möglicherweise nie entfernt oder geändert, ohne die Abwärtskompatibilität zu unterbrechen.

Memberschnittstellenversionsverwaltung

Memberschnittstellen für Laufzeitklassen sind additiv versionsierbar. Nachfolgende Versionen einer bestimmten Laufzeitklasse können zusätzliche Memberschnittstellen implementieren, auch wenn die Klasse zuvor nie Memberschnittstellen implementiert hatte. Nachfolgende Versionen einer bestimmten composablen Laufzeitklasse können zusätzliche geschützte und außerkraftsetzende Schnittstellen implementieren.

Schnittstellen, die von einer Laufzeitklasse implementiert werden, tragen optional das VersionAttribute-Objekt, um zu unterscheiden, wann bestimmte Schnittstellen dem Laufzeitklassentyp hinzugefügt wurden. Schnittstellenimplementierungswerte ohne VersionAttribute gelten als denselben Versionswert wie der eingeschlossene Laufzeitklassentyp.

Statische Schnittstellenversionsverwaltung

Statische Schnittstellen für Laufzeitklassen sind additiv versionsierbar. Nachfolgende Versionen einer bestimmten Laufzeitklasse können zusätzliche statische Schnittstellen implementieren, auch wenn die Klasse zuvor noch nie statische Schnittstellen implementiert hatte.

Das StaticAttribute enthält einen UInt32-Parameter für die Versionsnummer, der die Version von Windows definiert, die diese Aktivierungsunterstützung hinzugefügt hat.

Aktivierungsversionsverwaltung

Aktivierungsunterstützung für Laufzeitklassen ist additiv versionierbar. Nachfolgende Versionen einer bestimmten Laufzeitklasse können zusätzliche Aktivierungsmechanismen implementieren, auch wenn die Klasse nie einen Aktivierungsmechanismus implementiert hatte. Beachten Sie, dass composable Klassen nicht aktiviert werden können und daher keine Aktivierungsunterstützung hinzufügen.

Beachten Sie, dass eine Klasse, die die direkte Aktivierung unterstützt, nur neue Factoryaktivierungsschnittstellen hinzufügen. Eine Klasse, die zuvor nur die unterstützte Fabrikaktivierung unterstützt, kann direkte Aktivierungsunterstützung sowie neue Factoryaktivierungsschnittstellen hinzufügen.

Das AktivierenableAttribute enthält einen UInt32-Parameter für die Versionsnummer. Die Versionsnummer für das AktivierenableAttribute definiert die Version von Windows, die diese Aktivierungsunterstützung hinzugefügt hat.

Kompositionsversionierung

Die Kompositionsunterstützung für Laufzeitklassen ist additiv versionierbar. Nachfolgende Versionen einer bestimmten composablen Laufzeitklasse können zusätzliche Kompositionsmechanismen implementieren, sofern die Klasse beim Erstellen als kompposierbar definiert wurde. Composable-Klassen fügen möglicherweise keine Aktivierungsunterstützung hinzu.

Das ComposableAttribute enthält einen UInt32-Parameter für die Versionsnummer. Die Versionsnummer für das ComposableAttribute definiert die Version von Windows, die diese Kompositionsunterstützung hinzugefügt hat.

Benutzerdefinierte Attribute

WinRT unterstützt die Definition von benutzerdefinierten Metadatenattributen. Alle Konstrukte im WinRT-Typsystem können benutzerdefinierte Metadatenattribute tragen. Dazu gehören alle benannten Typen (Enums, Struktur, Stellvertretungen, Schnittstellen, Klassen usw.) sowie einzelne Elemente, die innerhalb von Typkonstrukten enthalten sind (z. B. Methoden, Parameter usw.).

Benutzerdefinierte Attribute werden wie andere WinRT-Typen benannt. Sie sind jedoch nicht aktivierbar. Sie sind nur ein Datenkonstrukt.

Benutzerdefinierte Attribute definieren ein Datenschema von Positionalparametern oder benannten Feldern. Ein benutzerdefiniertes Attribut verwendet möglicherweise nicht sowohl Positionsparameter als auch benannte Felder– es muss eine oder andere auswählen. Die Typen der Parameter und Felder eines benutzerdefinierten Attributs sind auf die grundlegenden WinRT-Typen, Aufzählungen und Verweise auf andere WinRT-Typen beschränkt. Kein anderer Parameter oder Feldtyp ist zulässig.

Benutzerdefinierte Attribute, die Positionalparameter verwenden, müssen mindestens eine gültige Reihe von Positionsparametern definieren. Jeder Satz muss null oder mehr Positionsparameter angeben. Eine Instanz des benutzerdefinierten Attributs muss eine einzelne Gruppe von Positionsparametern sowie Daten für jeden Positionalparameter im ausgewählten Satz angeben.

Ein benutzerdefiniertes Attribut, das benannte Felder verwendet, gibt Nullfelder mit Namen und Typen an. Eine Instanz des benutzerdefinierten Attributs muss die Namen-/Wertpaare für die Felder angeben, die sie angeben möchten. Eine Instanz kann Werte für alle, einige oder keine der Namen/Wertpaare angeben.

Es ist gültig, dass ein Attribut weder Positionalparameter noch benannte Felder enthält.

Ein benutzerdefiniertes Attribut muss über öffentliche Sichtbarkeit verfügen.

Ein Attribut kann die Typen des WinRT-Typs angeben, mit denen er über das AttributUsageAttribute verknüpft werden kann.

Drittanbieter können keine benutzerdefinierten Attribute definieren. Nur die benutzerdefinierten Attribute, die vom System definiert sind, werden unterstützt.