Rubriques avancées et raccourcis

Forme abrégée

Si vous utilisez un type paramétrable sans spécifier d’espace de noms, le compilateur MIDL 3,0 le recherche dans le Windows. Espace de noms Foundation. Collections. Dans la pratique, cela signifie que vous pouvez utiliser le raccourci suivant.

Version abrégée Version longue
IIterable<T> Windows. Foundation. Collections. interface iiterable < T>
IIterator < T> Windows. Foundation. Collections. IIterator < T>
IKeyValuePair < K, V> Windows. Foundation. Collections. IKeyValuePair < K, V>
IMap<K, V> Windows. Foundation. Collections. IMap < K, V>
IMapChangedEventArgs < K> Windows. Foundation. Collections. IMapChangedEventArgs < K>
IMapView<K, V> Windows. Foundation. Collections. IMapView < K, V>
IObservableMap < K, V> Windows. Foundation. Collections. IObservableMap < K, V>
IObservableVector < T> Windows. Foundation. Collections. IObservableVector < T>
IVector<T> Windows. Foundation. Collections. IVector < T>
IVectorView<T> Windows. Foundation. Collections. IVectorView < T>
MapChangedEventHandler < K, V> Windows. Foundation. Collections. MapChangedEventHandler < K, V>
VectorChangedEventHandler < T> Windows.Foundation.Collections.VectorChangedEventHandler<T>

Ce mécanisme ne s’applique pas au Windows. Espace de noms Foundation. Par exemple, vous devez écrire le nom complet Windows. Foundation. IAsyncAction.

Surcharges

Le comportement par défaut pour les méthodes et les constructeurs surchargés consiste à ajouter un suffixe numérique aux noms ABI pour la deuxième surcharge et les surcharges suivantes dans une interface.

[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);
    }
}

Ce nom par défaut ne correspond pas aux règles de conception d’API recommandées. par conséquent, remplacez-le par l’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);
    }
}

Implémenter une interface non exclusiveto

La dérivation de la classe d’exécution à partir d’une interface déclare automatiquement les membres de cette interface. Ne les redéclarez pas. Dans ce cas, le compilateur MIDL 3,0 suppose que vous souhaitez implémenter une méthode distincte M () qui masque celle-ci de l’interface.

interface I
{
    void M();
}

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

Spécifier l’interface par défaut

Si vous ne spécifiez pas d’interface par défaut, le compilateur MIDL 3,0 choisit la première interface d’instance. Pour remplacer cette sélection, insérez l’attribut [default] avant l’interface que vous souhaitez utiliser comme interface par défaut.

// 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(...)]
    {
        ...
    }
}

Attributs de compatibilité descendante

Si vous convertissez MIDL 1,0 ou MIDL 2,0 en MIDL 3,0 (voir également la transition vers midl 3,0 à partir de MIDLRT classiques), vous devrez personnaliser les éléments qui sont généralement générés automatiquement afin que les valeurs générées automatiquement correspondent à celles existantes.

  • Pour spécifier le nom et l’UUID d’une interface, utilisez l' [interface_name("fully.qualified.name", UUID)] attribut.
  • Pour spécifier le nom et l’UUID d’une interface de fabrique, utilisez l' [constructor_name("fully.qualified.name", UUID)] attribut.
  • Pour spécifier le nom et l’UUID d’une interface statique, utilisez l' [static_name("fully.qualified.name", UUID)] attribut.
  • Pour spécifier le nom d’un paramètre de sortie, utilisez l' [return_name("name")] attribut.
  • Pour spécifier le nom d’une méthode, utilisez l' [method_name("name")] attribut.

La partie « UUID » des interface_name attributs, constructor_name et static_name est facultative. En cas d’omission, MIDL génère automatiquement un 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();
    }
}

Le compilateur MIDL 3,0 ne vous avertira pas si vous recevez xxx_name une annotation confuse. Par exemple, l’exemple suivant se compile sans erreur, même s’il n’y a pas de membres d’instance à placer dans l' interface_name interface. La présence de l' interface_name attribut entraîne la génération d’une interface vide nommée ISampleFactory2 .

[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);
   }
}

Classes vides

Bien que cette utilisation soit quelque peu obscurcie, il est parfois nécessaire de créer une classe vide (une classe sans membres) ou une classe de fabrique vide. Un exemple courant de cela se produit avec une classe EventArgs . Si un événement est introduit, il n’est pas nécessaire d’utiliser des arguments pour l’événement (l’événement signalé ne nécessite pas de contexte supplémentaire). Nos instructions de conception d’API recommandent fortement qu’une classe EventArgs soit fournie, ce qui permet à la classe d’ajouter de nouveaux arguments d’événement à l’avenir. Toutefois, envisagez cette classe vide.

runtimeclass MyEventsEventArgs
{
}

Cette classe génère cette erreur.

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' ) ]

Il existe plusieurs façons de résoudre ce problème. La plus simple consiste à utiliser l' [default_interface] attribut pour exprimer que l’absence de méthodes est intentionnelle, et non pas une erreur de création. Voici comment procéder.

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

Une autre façon de résoudre ce problème est d’utiliser l' [interface_name] attribut. Si MIDL rencontre le [interface_name] sur une classe sans méthode normale (ou un bloc avec version sans méthode normale), il génère une interface vide pour ce bloc. De même, si l' [static_name] attribut ou [constructor_name] est présent sur une classe ou un bloc avec version sans aucun (ou constructeur) statique, il génère une interface vide pour cette interface ou ce constructeur statique.

Veillez à ne pas confondre une classe vide avec une classe statique. Vous pouvez avoir des instances d’une classe vide (même si elles ne font rien), mais vous ne pouvez pas avoir d’instances d’une classe statique.

Interfaces vides

Une interface vide (également appelée interface de marqueur) doit spécifier un explicite [uuid(...)] .

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

Si vous l’oubliez, cette erreur est générée.

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

Les UUID générés automatiquement sont un hachage du contenu de l’interface, mais si cela a été fait pour les interfaces vides, toutes les interfaces des marqueurs finissent par le même UUID.

Enums délimités

Si vous passez le /enum_class commutateur de commande au compilateur MIDL 3,0, les énumérations émises par le compilateur sont déclarées comme des enums délimités (classe enum). N’utilisez pas d’enums délimités pour les types publics.

Composition et activation

Pour plus d’informations sur les classes composables , consultez contrôles XAML ; lier à une propriété C++/WinRT.

Vous pouvez spécifier unsealed runtimeclass pour créer une classe composable. En outre, vous pouvez spécifier unsealed runtimeclass unsealed pour indiquer si la classe utilise l’agrégation com ou l’activation régulière. Cela est important pour les classes de base avec des constructeurs publics.

Interprétation des messages d’erreur

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

Si vous écrivez IAsyncOperation<IVectorView<Something>> , est interprété comme un opérateur de décalage vers la >> droite. Pour contourner ce contournement, insérez un espace entre les deux signes supérieur à IAsyncOperation<IVectorView<Something> > .

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

Cette erreur se produit si vous spécifiez un contrat inexistant, peut-être en raison d’une faute de frappe.

[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

Ce message d’erreur est généré non seulement pour la raison dans le message d’erreur, mais également si vous tentez de placer les champs d’une énumération dans des contrats différents. Il est autorisé de faire en sorte que les champs d’une énumération appartiennent à différentes versions du même contrat, mais qu’ils ne puissent pas être entièrement dans des contrats différents.

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

Les noms result de paramètres et operation sont réservés dans les méthodes. Le nom value du paramètre est réservé dans les constructeurs.

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

Vérifiez que vous avez correctement orthographié le nom de l’interface.

Ne mélangez pas MIDL 2,0 et MIDL 3,0 dans une seule interface

Chaque classe d’interface et d’exécution doit être entièrement MIDL 2,0 ou complètement MIDL 3,0. Il est légal de référencer une interface MIDL 3,0 à partir d’une classe d’exécution MIDL 2,0.

Si vous essayez de mélanger MIDL 2,0 et MIDL 3,0, le compilateur traite l’ensemble de l’entité comme MIDL 2,0, ce qui génère des erreurs de compilation. Vous pouvez rencontrer ce problème si vous utilisez accidentellement la syntaxe MIDL 2,0 quand vous avez prévu d’utiliser MIDL 3,0.

interface ICollapsible
{
    void Collapse();

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

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

Délégués retournant HRESULT

Un délégué qui retourne un HRESULT est ambigu. Il peut s’agir d’une déclaration classique (pré-MIDL 3,0) d’un délégué qui retourne symboliquement void (où HRESULT est utilisé pour propager une exception), ou il peut s’agir d’une déclaration moderne (MIDL 3,0) d’un délégué qui retourne un HRESULTde façon symbolique.

Le compilateur résout l’ambiguïté en examinant d’autres parties de la déclaration. Par exemple, si les paramètres sont déclarés avec la syntaxe classique, la déclaration est supposée être classique. Si les paramètres sont déclarés avec la syntaxe moderne, la déclaration est supposée être moderne.

delegate HRESULT AmbiguousDelegate(INT32 value, RuntimeClassName* r);
  • Comme les paramètres utilisent la syntaxe classique, il est supposé qu’il s’agit d’une déclaration classique.
  • L’équivalent moderne est delegate void AmbiguousDelegate(Int32 value, RuntimeClassName r); .
delegate HRESULT AmbiguousDelegate(Int32 value, RuntimeClassName r);
  • Comme les paramètres utilisent la syntaxe moderne, il est supposé qu’il s’agit d’une déclaration moderne.
  • L’équivalent classique est delegate HRESULT AmbiguousDelegate(Int32 value, RuntimeClassName* r, [out, retval] HRESULT* result); .

Parfois, la liste des paramètres est insuffisante pour résoudre l’ambiguïté. Par exemple, une liste de paramètres vide ou une liste de paramètres qui se compose uniquement d’enums est conforme à la fois dans la syntaxe classique et moderne. Dans ce cas, le compilateur MIDL 3,0 est défini par défaut sur Classic.

delegate HRESULT AmbiguousDelegate(MyEnum e);
  • Interprété comme un délégué classique, où le délégué retourne une valeur void, et la valeur HRESULT correspond à la propagation d’une exception.
  • Si vous voulez vraiment qu’un délégué retournait un HRESULT, vous devez utiliser la syntaxe classique : delegate HRESULT AmbiguousDelegate(MyEnum e, [out, retval] HRESULT* result); .

Heureusement, il est rare d’avoir un délégué qui retourne une valeur HRESULT.

Paramètres de sortie en JavaScript et Visual Basic

Consultez paramètres pour obtenir des informations générales sur les paramètres de sortie.

JavaScript projette une méthode avec un out paramètre différent de la plupart des langues. Si le type de retour d’une méthode est void et qu’il a un seul out paramètre, le out paramètre est retourné par la méthode. Sinon, la méthode retourne un objet unique ; cet objet a une propriété pour chaque out paramètre, plus une autre propriété pour la valeur de retour (si elle n’est pas void). Dans l’exemple suivant, l’objet JavaScript retourné par l’appel de méthode a une propriété nommée resultet une autre propriété nommée Remainder.

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

Visual Basic ne prend pas en charge out les paramètres uniquement. une méthode avec des out paramètres est traitée par Visual Basic comme si elle était ByRef .