Erweiterte Themen und Kurzformen

Kompakt

Wenn Sie einen parametrisierten Typ verwenden, ohne einen Namespace anzugeben, sucht der MIDL 3.0-Compiler im Windows danach. Foundation.Collections-Namespace. In der Praxis bedeutet dies, dass Sie die folgende Kurzform verwenden können.

Kurzversion Lange Version
IIterable<T> Windows. Foundation.Collections.IIterableT<>
IIteratorT<> Windows. Foundation.Collections.IIteratorT<>
IKeyValuePairK<, V> Windows. Foundation.Collections.IKeyValuePairK<, V>
IMap<K, V> Windows. Foundation.Collections.IMapK<, V>
IMapChangedEventArgsK<> Windows. Foundation.Collections.IMapChangedEventArgsK<>
IMapView<K, V> Windows. Foundation.Collections.IMapViewK<, V>
IObservableMapK<, V> Windows. Foundation.Collections.IObservableMapK<, V>
IObservableVectorT<> Windows. Foundation.Collections.IObservableVectorT<>
IVector<T> Windows. Foundation.Collections.IVectorT<>
IVectorView<T> Windows. Foundation.Collections.IVectorViewT<>
MapChangedEventHandlerK<, V> Windows. Foundation.Collections.MapChangedEventHandlerK<, V>
VectorChangedEventHandlerT<> Windows.Foundation.Collections.VectorChangedEventHandler<T>

Dieser Mechanismus gilt nicht für die Windows. Basisnamespace. Beispielsweise müssen Sie den vollständigen Namen Windows schreiben. Foundation.IAsyncAction.

Überlädt

Das Standardverhalten für überladene Methoden und Konstruktoren besteht darin, ein numerisches Suffix an die ABI-Namen für die zweite und nachfolgende Überladungen innerhalb einer Schnittstelle anzufügen.

[contract(Windows.Foundation.UniversalApiContract, 1)]
runtimeclass Sample
{
    // ABI name is "DoSomething"
    void DoSomething();

    // ABI name is "DoSomething2"
    void DoSomething(Int32 intensity);

    [contract(Windows.Foundation.UniversalApiContract, 2)]
    {
        // ABI name is "DoSomething" (new interface)
        void DoSomething(Int32 intensity, String label);
    }
}

Diese Standardbenennung entspricht nicht den empfohlenen API-Entwurfsrichtlinien. Überschreiben Sie sie daher mit dem Attribut [method_name].

[contract(Windows.Foundation.UniversalApiContract, 1)]
runtimeclass Sample
{
    void DoSomething();

    [method_name("DoSomethingWithIntensity")]
    void DoSomething(Int32 intensity);

    [contract(Windows.Foundation.UniversalApiContract, 2)]
    {
        [method_name("DoSomethingWithIntensityAndLabel")]
        void DoSomething(Int32 intensity, String label);
    }
}

Implementieren einer nicht exklusivento-Schnittstelle

Wenn Sie Ihre Laufzeitklasse von einer Schnittstelle ableiten, werden die Member dieser Schnittstelle automatisch deklariert. Deklarieren Sie sie nicht erneut. Wenn Sie dies tun, geht der MIDL 3.0-Compiler davon aus, dass Sie eine separate M() -Methode implementieren möchten, die die Methode aus der Schnittstelle ausblendet.

interface I
{
    void M();
}

runtimeclass C : I
{
    // Don't redeclare M(). It's automatically inherited from interface I.
    // void M();
}

Angeben der Standardschnittstelle

Wenn Sie keine Standardschnittstelle angeben, wählt der MIDL 3.0-Compiler die erste Instanzschnittstelle aus. Um diese Auswahl zu überschreiben, fügen Sie das -Attribut [default] vor der Schnittstelle ein, die Sie als Standardschnittstelle verwenden möchten.

// Declaring an external interface as the default
runtimeclass C : [default]I { ... }

// Declaring a specific exclusiveto interface as the default.
// This is very unusual.
runtimeclass C
{
    ...

    [default][interface_name(...)]
    {
        ...
    }
}

Abwärtskompatibilitätsattribute

Wenn Sie MIDL 1.0 oder MIDL 2.0 in MIDL 3.0 konvertieren (siehe auch Übergang zu MIDL 3.0 vom klassischen MIDLRT), müssen Sie Dinge anpassen, die normalerweise automatisch generiert werden, sodass die automatisch generierten Werte mit den vorhandenen übereinstimmen.

  • Verwenden Sie das -Attribut, um den Namen und die [interface_name("fully.qualified.name", UUID)] UUID einer Schnittstelle anzugeben.
  • Verwenden Sie das -Attribut, um den Namen und die [constructor_name("fully.qualified.name", UUID)] UUID einer Factoryschnittstelle anzugeben.
  • Verwenden Sie das -Attribut, um den Namen und die [static_name("fully.qualified.name", UUID)] UUID einer statischen Schnittstelle anzugeben.
  • Verwenden Sie das -Attribut, um den Namen eines Ausgabeparameters [return_name("name")]anzugeben.
  • Verwenden Sie das -Attribut, um den [method_name("name")] Namen einer Methode anzugeben.

Der "UUID"-Teil der interface_nameAttribute , constructor_nameund static_name ist optional. Wenn keine Angabe erfolgt, generiert MIDL automatisch eine IID.

[contract(Windows.Foundation.UniversalApiContract, 1)]
[interface_name("ISample", ceb27355-f772-407c-9540-6467a7199bc7)]
[constructor_name("ISampleFactory", 863B201F-BC7B-471E-A066-6425E8E639EC)]
[static_name("ISampleStatics", 07254c86-3b01-4e24-b52b-14e832c15483)]
runtimeclass Sample
{
    [method_name("CreateWithIntensity")]
    Sample(Int32 intensity);

    static Boolean ShowConfigurationUI();

    [return_name("count")]
    Int32 GetCount();

    [constructor_name("ISampleFactory2", FEA29CEC-7768-41DE-9A46-CAAAA4622588)]
    [static_name("ISampleStatics2", 191235b5-a7b5-456f-86ea-abd1a735c6ab)]
    [interface_name("ISample2", d870ed2e-915a-48a2-ad17-c05efa123db7)]
    [contract(Windows.Foundation.UniversalApiContract, 2)]
    {
        [method_name("CreateWithIntensityAndLabel")]
        Sample(Int32 intensity, String label);

        static Boolean IsSupported();

        [return_name("success")]
        Boolean TrySomething();
    }
}

Der MIDL 3.0-Compiler warnt Sie nicht, wenn Ihre xxx_name Anmerkung verwechselt wird. Im folgenden Beispiel wird beispielsweise ohne Fehler kompiliert, auch wenn keine Instanzmember in der interface_name -Schnittstelle zu setzen sind. Das Vorhandensein des interface_name -Attributs bewirkt, dass eine leere Schnittstelle namens ISampleFactory2 generiert wird.

[contract(Windows.Foundation.UniversalApiContract, 1)]
[interface_name("ISample", ceb27355-f772-407c-9540-6467a7199bc7)]
runtimeclass Sample
{
    [return_name("count")]
    Int32 GetCount();

    // !WRONG! Should be constructor_name.
    [interface_name("ISampleFactory2", FEA29CEC-7768-41DE-9A46-CAAAA4622588)]
    [contract(Windows.Foundation.UniversalApiContract, 2)]
    {
        // MIDL will autogenerate ISampleFactory since there is no [constructor_name]
        Sample(Int32 intensity);
   }
}

Leere Klassen

Obwohl diese Verwendung etwas verdeckt ist, ist es manchmal notwendig, eine leere Klasse (eine Klasse ohne Member) oder eine leere Factoryklasse zu erstellen. Ein häufiges Beispiel hierfür ist eine EventArgs-Klasse . Wenn ein Ereignis eingeführt wird, sind manchmal keine Argumente für das Ereignis erforderlich (das signalisierte Ereignis erfordert keinen zusätzlichen Kontext). In unseren API-Entwurfsrichtlinien wird dringend empfohlen, eine EventArgs-Klasse zur Verfügung zu stellen, sodass die Klasse in Zukunft neue Ereignisargumente hinzufügen kann. Betrachten Sie diese leere Klasse jedoch.

runtimeclass MyEventsEventArgs
{
}

Diese Klasse erzeugt diesen Fehler.

error MIDL5056 : [msg]a runtime class without a default attribute cannot be used as a parameter. Runtime classes must have methods or be flagged as marker classes if they are used as a parameter [context]: Windows.Widgets.MyEventsEventArgs [ RuntimeClass 'Windows.Widgets.MyEventsEventArgs' ( Parameter 'result' ) ]

Es gibt mehrere Möglichkeiten, dies zu beheben. Die einfachste Möglichkeit besteht darin, das [default_interface] -Attribut zu verwenden, um auszudrücken, dass der Mangel an Methoden beabsichtigt und kein Erstellungsfehler ist. Hierzu gehst du wie folgt vor.

// An empty runtime class needs a [default_interface] tag to indicate that the 
// emptiness is intentional.
[default_interface] 
runtimeclass MyEventsEventArgs
{
}

Eine weitere Möglichkeit, dies zu beheben, ist das [interface_name] -Attribut. Wenn MIDL für [interface_name] eine Klasse ohne normale Methoden (oder einen Block mit Versionsbeschriftung ohne normale Methoden) auffindet, generiert sie eine leere Schnittstelle für diesen Block. Wenn das -Attribut oder [constructor_name] das [static_name] -Attribut in einer Klasse oder einem Versionsblock ohne statische (oder Konstruktoren) vorhanden ist, generiert es eine leere Schnittstelle für diese statische Schnittstelle oder diesen statischen Konstruktor.

Achten Sie darauf, eine leere Klasse nicht mit einer statischen Klasse zu verwechseln. Sie können Über Instanzen einer leeren Klasse verfügen (obwohl sie nichts tun), aber Sie können keine Instanzen einer statischen Klasse haben.

Leere Schnittstellen

Eine leere Schnittstelle (auch als Markerschnittstelle bezeichnet) muss eine explizite [uuid(...)]angeben.

// An empty interface must specify an explicit [uuid] to ensure uniqueness.
[uuid("94569FA9-D3BB-4D01-BF7C-B8E1D8F8B30C")]
[contract(Windows.Foundation.UniversalApiContract, 1)]
interface ISomethingMarker
{
}

Wenn Sie vergessen, wird dieser Fehler erzeugt.

error MIDL4010 : [msg]Cannot find the guid attribute of an interface or a delegate. [context]Windows.Widgets.ISomethingMarker

Automatisch generierte UUIDs sind ein Hash des Schnittstelleninhalts. Wenn dies jedoch für leere Schnittstellen erfolgt, erhalten alle Markerschnittstellen die gleiche UUID.

Bereichsbereichsenumer

Wenn Sie den /enum_class Befehlsschalter an den MIDL 3.0-Compiler übergeben, werden die vom Compiler ausgegebenen Enumerationen als Bereichsenumerationen (Enumerationsklasse) deklariert. Verwenden Sie keine bereichsweisen Enumerationen für öffentliche Typen.

Komposition und Aktivierung

Weitere Informationen zu zusammensetzbaren Klassen finden Sie unter XAML-Steuerelemente; Binden an eine C++/WinRT-Eigenschaft.

Sie können angeben unsealed runtimeclass , dass eine composable-Klasse erstellt werden soll. Darüber hinaus können Sie angeben unsealed runtimeclass unsealed , ob die Klasse die COM-Aggregation oder die reguläre Aktivierung verwendet. Dies ist für Basisklassen mit öffentlichen Konstruktoren von Bedeutung.

Interpretieren von Fehlermeldungen

error MIDL2025: [msg]syntax error [context]: expecting > or, near ">>"

Wenn Sie schreiben IAsyncOperation<IVectorView<Something>>, wird als >> Rechtsschiebeoperator interpretiert. Um dies zu umgehen, legen Sie ein Leerzeichen zwischen den beiden Größer-als-Zeichen, um zu geben IAsyncOperation<IVectorView<Something> >.

error MIDL2025: [msg]syntax error [context]: expecting . near ","

Dieser Fehler tritt auf, wenn Sie einen nicht vorhandenen Vertrag angeben, möglicherweise aufgrund eines Tippfehlers.

[contract(Windows.Foundation.UniversalApiContact, 5)]
                                         ^^^^^^^ typo
error MIDL5082: [msg]the version qualifying an enum's field cannot be less than the version of the enum itself

Diese Fehlermeldung wird nicht nur aus dem Grund in der Fehlermeldung generiert, sondern auch, wenn Sie versuchen, die Felder einer Enumeration in verschiedene Verträge zu integrieren. Es ist zulässig, dass die Felder einer Enumeration zu verschiedenen Versionen desselben Vertrags gehören, aber sie können nicht vollständig in unterschiedlichen Verträgen enthalten sein.

error MIDL5161: [msg]Invalid method parameter name [context]: Parameter 'result' (or 'operation' or 'value')

Parameternamen result und operation sind in Methoden reserviert. Der Parametername value ist in Konstruktoren reserviert.

error MIDL5023: [msg]the arguments to the parameterized interface are not valid

Überprüfen Sie, ob Sie den Schnittstellennamen richtig geschrieben haben.

Kombinieren Sie MIDL 2.0 und MIDL 3.0 nicht innerhalb einer einzigen Schnittstelle.

Jede Schnittstelle und Laufzeitklasse muss entweder vollständig MIDL 2.0 oder vollständig MIDL 3.0 sein. Es ist zulässig, von einer MIDL 2.0-Laufzeitklasse auf eine MIDL 3.0-Schnittstelle zu verweisen.

Wenn Sie versuchen, MIDL 2.0 und MIDL 3.0 zu mischen, behandelt der Compiler die gesamte Entität als MIDL 2.0, was zu Compilerfehlern führt. Sie können auf dieses Problem stoßen, wenn Sie versehentlich die MIDL 2.0-Syntax verwenden, wenn Sie MIDL 3.0 verwenden wollten.

interface ICollapsible
{
    void Collapse();

    boolean IsCollapsed { get; } // WRONG!
 // ^^^^^^^ Lowercase "boolean" is MIDL 2.0.

    Boolean IsCollapsed { get; } // RIGHT!
 // ^^^^^^^ Uppercase "Boolean" is MIDL 3.0.
};

Delegaten, die HRESULT zurückgeben

Ein Delegat, der ein HRESULT zurückgibt, ist mehrdeutig. Es kann sich um eine klassische (vor MIDL 3.0) Deklaration eines Delegaten, der nominell void zurückgibt (wobei das HRESULT verwendet wird, um eine Ausnahme zu übergeben) oder eine moderne (MIDL 3.0)-Deklaration eines Delegaten sein, der nominell ein HRESULT zurückgibt.

Der Compiler löst die Mehrdeutigkeit auf, indem er andere Teile der Deklaration betrachtet. Wenn die Parameter beispielsweise mit klassischer Syntax deklariert werden, wird davon ausgegangen, dass die Deklaration klassisch ist. Wenn die Parameter mit moderner Syntax deklariert werden, wird davon ausgegangen, dass die Deklaration modern ist.

delegate HRESULT AmbiguousDelegate(INT32 value, RuntimeClassName* r);
  • Parameter verwenden klassische Syntax, daher wird davon ausgegangen, dass es sich um eine klassische Deklaration handelt.
  • Die moderne Entsprechung ist delegate void AmbiguousDelegate(Int32 value, RuntimeClassName r);.
delegate HRESULT AmbiguousDelegate(Int32 value, RuntimeClassName r);
  • Parameter verwenden moderne Syntax, daher wird davon ausgegangen, dass es sich um eine moderne Deklaration handelt.
  • Das klassische Äquivalent ist delegate HRESULT AmbiguousDelegate(Int32 value, RuntimeClassName* r, [out, retval] HRESULT* result);.

Manchmal reicht die Parameterliste nicht aus, um die Mehrdeutigkeit aufzulösen. Beispielsweise ist eine leere Parameterliste oder eine Parameterliste, die nur aus Enums besteht, sowohl in der klassischen als auch in der modernen Syntax legal. In solchen Fällen wird der MIDL 3.0-Compiler standardmäßig auf klassisch festgelegt.

delegate HRESULT AmbiguousDelegate(MyEnum e);
  • Wird als klassischer Delegat interpretiert, wobei der Delegat nominell void zurückgibt und das HRESULT für die Propagierung einer Ausnahme ist.
  • Wenn Sie einen Delegaten wirklich benötigen, der ein HRESULT zurückgegeben hat, müssen Sie die klassische Syntax verwenden: delegate HRESULT AmbiguousDelegate(MyEnum e, [out, retval] HRESULT* result);.

Glücklicherweise ist es selten, einen Delegaten zu haben, der nominal HRESULT zurückgibt.

Ausgabeparameter in JavaScript und Visual Basic

Hintergrundinformationen zu Ausgabeparametern finden Sie unter Parameter.

JavaScript projektiert eine Methode mit einem Parameter out anders als die meisten Sprachen. Wenn der Rückgabetyp einer Methode void ist und out über einen einzelnen Parameter verfügt, out wird der Parameter von der -Methode zurückgegeben. Andernfalls gibt die Methode ein einzelnes -Objekt zurück. dieses Objekt verfügt über eine -Eigenschaft für jeden out Parameter sowie eine weitere Eigenschaft für den Rückgabewert (falls nicht void). Im folgenden Beispiel verfügt das vom Methodenaufruf zurückgegebene JavaScript-Objekt über eine Eigenschaft namens result und eine weitere Eigenschaft namens remainder.

runtimeclass Test
{
    static void Divide(Int32 x, Int32 y, out Int32 result, out Int32 remainder);
}

Visual Basic -Parameter werden nicht outunterstützt. Eine Methode mit out Parametern wird von Visual Basic behandelt, als wäre sie ByRef.