Attributs prédéfinis (MIDL 3.0)

Il existe un certain nombre d’attributs personnalisés prédéfinis qui vous permettent de contrôler le nom et l’identificateur d’interface (IID) pour les interfaces synthétisées par le compilateur. Ces attributs vous permettent de contrôler le contrôle de version et l’API binaire de votre classe à un niveau affiné.

Si vous êtes un développeur de composants et/ou un auteur de bibliothèque, vous souhaiterez peut-être utiliser ces attributs pour vous assurer que vos composants restent stables au format binaire d’une version à l’autre.

Si vous êtes développeur d’applications, en général vous n’aurez pas besoin d’utiliser ces attributs, car vous recompilerez votre application après avoir recompilé vos types.

L' [allowforweb] attribut

Pour plus d’informations sur l’utilisation et l’objectif de l' allowforweb attribut, consultez la classe AllowForWebAttribute.

L' [constructor_name] attribut

L' constructor_name attribut spécifie le nom et l’IID de l’interface de fabrique qui contient les membres du constructeur. Pour plus d’informations sur les interfaces de fabrique, consultez synthèse des interfaces .

Notes

Une interface de fabrique s’applique uniquement à une classe scellée avec des constructeurs autres que ceux par défaut, ou à une classe non scellée avec des constructeurs par défaut et/ou des constructeurs non définis par défaut.

Dans l’exemple ci-dessous, le constructeur de bloc protégé est placé dans l’interface IBlockFactory , et cette interface a l’IID spécifié.

[constructor_name("Windows.UI.Xaml.Documents.IBlockFactory", 07110532-4f59-4f3b-9ce5-25784c430507)]
...
unsealed runtimeclass Block : Windows.UI.Xaml.Documents.TextElement
{
    ...
    protected Block();
    ...
}

Par conséquent, lorsque la description de votre classe ne fait pas référence à une interface, mais lorsque l’un d’eux est nécessaire pour implémenter la classe, le compilateur MIDL 3,0 synthétise et ajoute des interfaces, si nécessaire.

L' [contentproperty] attribut

l' contentproperty attribut représente la classe ContentPropertyAttribute . Voici un exemple :

// BgLabelControl.idl
namespace BgLabelControlApp
{
    [contentproperty("Content")]
    runtimeclass BgLabelControl : Windows.UI.Xaml.Controls.Control
    {
        BgLabelControl();
        static Windows.UI.Xaml.DependencyProperty LabelProperty{ get; };
        String Label;
        static Windows.UI.Xaml.DependencyProperty ContentProperty{ get; };
        IInspectable Content;
    }
}

L' [contract] attribut

n’utilisez pas l' contract attribut dans vos propres api ; il n’a de signification que pour les api Windows intégrées.

l' contract attribut spécifie le nom et la version du contrat d’API Windows 10 (consultez programmation avec les kits de développementlogiciel (sdk) d’extension) dans lequel le type et/ou membre avec attributs a été introduit pour la première fois dans Windows (par conséquent, il n’est pas pertinent pour les api non remises dans le cadre de Windows). L’attribut prend la forme [contract(ContractName, ContractVersion)] et s’affiche avant l’élément auquel il s’applique.

L' [default] attribut

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' default attribut 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(...)]
    {
        ...
    }
}

L' [default_interface] attribut

L' default_interface attribut est utilisé pour forcer la génération d’une interface par défaut dans laquelle aucune autre valeur n’est générée. Dans l’exemple ci-dessous, StateTriggerBase n’a pas besoin d’une interface par défaut (étant donné qu’il n’a aucun membre non statique public), il ne s’agit donc que de la présence de l’attribut qui provoque la default_interface génération d’un (nommé IStateTriggerBase).

[default_interface]
unsealed runtimeclass StateTriggerBase
{
    protected void SetActive(Boolean IsActive);
};

L' [default_overload] attribut

Notes

Cet attribut n’est pas pris en charge pour les constructeurs. Si vous ne pouvez pas surcharger vos constructeurs par arité, vous pouvez définir des méthodes de fabrique surchargées, telles que les exemples CreateFromUri et CreateFromStream , présentées dans le dernier extrait de code de cette section.

L' default_overload attribut représente la classe DefaultOverloadAttribute , qui indique qu’une méthode est la méthode de surcharge par défaut. Cette section vous guide tout au long de la raison de et des instructions d’utilisation pour l' [default_overload] attribut.

vous pouvez surcharger librement les méthodes de Windows Runtime par arité. Autrement dit, vous pouvez définir plusieurs méthodes portant le même nom, à condition que chacune prenne un nombre d’arguments différent. À des fins de facilité d’utilisation, nous vous recommandons d’ajouter de nouveaux paramètres à la fin, et de faire en sorte que le comportement de la fonction de liste de paramètres plus petite soit équivalent à l’appel de la fonction de liste de paramètres plus longue avec des valeurs par défaut naturelles (spécifiques au scénario) pour les paramètres manquants.

runtimeclass Widget
{
    void Start();
    void Start(StartMode mode);
    void Start(StartMode mode, Widget parent);
}

Dans l’exemple ci-dessus, Start peut être appelé avec deux paramètres pour spécifier un mode de démarrage et un widget parent. Si vous omettez le widget parent, la valeur par défaut est null. Et si vous omettez le mode, il démarre dans un mode par défaut spécifique au scénario.

Nous utilisons DeviceInformation. CreateWatcher dans l’exemple suivant.

runtimeclass DeviceInformation
{
    static DeviceWatcher CreateWatcher();
    static DeviceWatcher CreateWatcher(DeviceClass deviceClass);
    static DeviceWatcher CreateWatcher(String aqsFilter);
    static DeviceWatcher CreateWatcher(String aqsFilter,
                                       IIterable<String> additionalProperties);
    static DeviceWatcher CreateWatcher(String aqsFilter,
                                       IIterable<String> additionalProperties,
                                       DeviceInformationKind kind);
}

Dans cet exemple, il y a cinq surcharges, et la plupart d’entre elles suivent le modèle recommandé pour que chaque nouvelle surcharge soit une extension de la surcharge précédente.

Si vous décidez d’avoir plusieurs surcharges d’une méthode avec le même nombre de paramètres, vous recevez une erreur du compilateur :

Les surcharges de paramètre 1 de DeviceInformation. CreateWatcher doivent avoir une seule méthode spécifiée en tant que surcharge par défaut en la décorant avec Windows. Foundation. Metadata. DefaultOverloadAttribute.

La raison en est que certains langages de programmation sont typés dynamiquement. JavaScript et Python sont deux exemples. Pour ces langues, la sélection de la surcharge ne prend en compte que le nombre de paramètres et non leurs types. Cela signifie qu’un appel JavaScript à DeviceInformation.createWatcher(v); est ambigu , doit- il être forcé à DeviceClassou à une chaîne?

Pour résoudre l’ambiguïté, vous devez appliquer l' [default_overload] attribut à l’une des méthodes. Mais comment choisir celui qui vous a été choisi ?

Vous devez choisir la surcharge par défaut afin que la fonctionnalité des surcharges non par défaut soit toujours disponible par d’autres moyens, en général par l’une des autres surcharges.

Dans l’exemple DeviceInformation. CreateWatcher , les fonctionnalités de la surcharge de chaîne peuvent être obtenues en appelant la chaîne, la surcharge de chaîne > interface iiterable < et en passant une liste de propriétés vide. En revanche, la surcharge DeviceClass est la seule façon de créer un DeviceWatcher qui est filtré vers un DeviceClass.

Cela fait de la méthode DeviceClass le gagnant clair. Vous indiquez donc cela en appliquant l' [default_overload] attribut à cette surcharge.

runtimeclass DeviceInformation
{
    static DeviceWatcher CreateWatcher();
    [default_overload]
    static DeviceWatcher CreateWatcher(DeviceClass deviceClass);
    static DeviceWatcher CreateWatcher(String aqsFilter);
    static DeviceWatcher CreateWatcher(String aqsFilter,
                                       IIterable<String> additionalProperties);
    static DeviceWatcher CreateWatcher(String aqsFilter,
                                       IIterable<String> additionalProperties,
                                       DeviceInformationKind kind);
}

Que se passe-t-il s’il n’y a aucun gagnant, car toutes les surcharges conflictuelles fournissent des fonctionnalités uniques qui ne sont pas disponibles à partir d’autres surcharges ?

runtimeclass Widget
{
    static Widget Create(Uri source);
    static Widget Create(IInputStream source);
}

Notre objet widget hypothétique peut être créé à partir d’un URIou créé à partir d’un flux d’entrée. Si vous en marquez une comme surcharge par défaut, les langages de programmation de type dynamique perdent complètement l’accès à l’autre.

Pour résoudre ce problème, donnez aux deux versions des noms différents afin qu’ils ne soient pas surchargés.

runtimeclass Widget
{
    static Widget CreateFromUri(Uri source);
    static Widget CreateFromStream(IInputStream source);
}

Désormais, les deux modèles de création sont disponibles pour tous les langages.

Consultez également surcharge de méthode et projection basée sur une classe.

L' [interface_name] attribut

L' interface_name attribut spécifie le nom et l’IID de l’interface qui contient les membres d’instance de la classe. Par défaut, le compilateur assigne des noms d’interface à l’aide du même algorithme de numérotation unique qu’il utilise pour les méthodes.

Dans l’exemple ci-dessous, l' interface_name attribut appliqué à runtimeclass spécifie le nom et l’IID de l’interface qui contient tous les membres d’instance de la classe qui ne sont pas assignés autrement à une interface. Par conséquent, LineHeight, LineStackingStrategy, Marginet TextAlignment sont membres de l’interface IBlock .

Toutefois, HorizontalTextAlignment est membre de l’interface IBlock2 , en raison de l' interface_name attribut qui englobe ce membre.

[interface_name("Windows.UI.Xaml.Documents.IBlock", 4bce0016-dd47-4350-8cb0-e171600ac896)]
...
unsealed runtimeclass Block : Windows.UI.Xaml.Documents.TextElement
{
    ...
    Double LineHeight;
    Windows.UI.Xaml.LineStackingStrategy LineStackingStrategy;
    Windows.UI.Xaml.Thickness Margin;
    Windows.UI.Xaml.TextAlignment TextAlignment;

    [interface_name("Windows.UI.Xaml.Documents.IBlock2", 5ec7bdf3-1333-4a92-8318-6caedc12ef89)]
    {
        Windows.UI.Xaml.TextAlignment HorizontalTextAlignment;
    }
    ...
}

Vous pouvez également utiliser l' interface_name attribut pour forcer la génération d’une interface. Dans l’exemple ci-dessous, StateTriggerBase n’a pas besoin de IStateTriggerBase, et il s’agit uniquement de la présence de l' interface_name attribut qui provoque sa génération.

[interface_name("Windows.UI.Xaml.IStateTriggerBase", 48b20698-af06-466c-8052-93666dde0e49)]
unsealed runtimeclass StateTriggerBase
{
    protected void SetActive(Boolean IsActive);
};

Par conséquent, lorsque la description de votre classe ne fait pas référence à une interface, mais lorsque l’un d’eux est nécessaire pour implémenter la classe, le compilateur MIDL 3,0 synthétise et ajoute des interfaces, si nécessaire.

Si vous utilisez default_interface inutilement, MIDL 3,0 génère une interface vide supplémentaire et en fait la valeur par défaut.

L' [method_name] attribut

chaque interface Windows Runtime a une interface ABI (Application Binary interface) équivalente. L’interface ABI requiert que tous les membres aient des noms uniques. Il existe deux cas dans MIDL 3,0 où les membres n’ont pas de nom, ou n’ont pas de nom unique.

  • constructeurs et
  • au moins deux méthodes surchargées.

Dans ces cas, le compilateur MIDL 3,0 synthétise un nom de membre unique, si nécessaire.

Par défaut, le compilateur assigne les méthodes de constructeur aux noms <className> , <className> 2, <className> 3, et ainsi de suite pour les méthodes équivalentes dans l’interface Abi. En d’autres termes, le plus petit suffixe de chiffre entier inutilisé (plus de 2) est ajouté pour rendre le nom de méthode du constructeur unique.

De même, pour les méthodes surchargées, pour la première méthode dans une série de surcharges (dans l’ordre lexical), le compilateur utilise le nom de méthode d’origine pour la méthode d’interface ABI équivalente. Les surcharges suivantes sont rendues uniques en ajoutant au nom d’origine le plus petit suffixe de chiffre entier inutilisé (à partir de 2).

Par exemple, l’IDL suivant déclare trois surcharges de l' opération de travail, et deux surcharges d’une méthode différente nommée DoWork3.

void DoWork(Int32 x);
void DoWork3(Int32 x);
void DoWork(Int32 x, Int32 y);
void DoWork(Int32 x, Int32 y, Int32 z);
void DoWork3(Int32 x, Int32 y);

Par défaut (étant donné que le nom DoWork3 est déjà utilisé), le compilateur donne aux trois surcharges du travail les noms

  • DoWork
  • DoWork2
  • DoWork4.

DoWork3 n’est pas une surcharge de tâche . Par défaut, le compilateur donne aux deux surcharges de DoWork3 les noms

  • DoWork3
  • DoWork32.

Dans l’ordre vtable, les fonctions s’affichent sous la forme

  • DoWork
  • DoWork3
  • DoWork2
  • DoWork4
  • DoWork32

Vous pouvez substituer l’assignation de nom par défaut du compilateur à l’aide de l' method_name attribut.

Dans l’exemple suivant, nous indiquons au compilateur d’utiliser le nom CreateInstance pour le membre de constructeur Block par défaut.

unsealed runtimeclass Block : Windows.UI.Xaml.Documents.TextElement
{
    ...
    [method_name("CreateInstance")] protected Block();
    ...
}

L' [static_name] attribut

L' static_name attribut spécifie le nom et l’IID de l’interface qui contient des membres statiques de la classe.

Dans l’exemple suivant, l' static_name attribut appliqué à runtimeclass spécifie le nom et l’IID de l’interface qui contient tous les membres statiques de la classe qui ne sont pas assignés autrement à une interface. Ainsi, LineHeightProperty, LineStackingStrategyProperty, MarginPropertyet TextAlignmentProperty sont membres de l’interface IBlockStatics .

Toutefois, HorizontalTextAlignmentProperty est membre de l’interface IBlockStatics2 , en raison de l' static_name attribut qui englobe ce membre.

[static_name("Windows.UI.Xaml.Documents.IBlockStatics", f86a8c34-8d18-4c53-aebd-91e610a5e010)]
...
unsealed runtimeclass Block : Windows.UI.Xaml.Documents.TextElement
{
    ...
    static Windows.UI.Xaml.DependencyProperty LineHeightProperty{ get; };
    static Windows.UI.Xaml.DependencyProperty LineStackingStrategyProperty{ get; };
    static Windows.UI.Xaml.DependencyProperty MarginProperty{ get; };
    static Windows.UI.Xaml.DependencyProperty TextAlignmentProperty{ get; };

    [static_name("Windows.UI.Xaml.Documents.IBlockStatics2", af01a4d6-03e3-4cee-9b02-2bfc308b27a9)]
    {
        static Windows.UI.Xaml.DependencyProperty HorizontalTextAlignmentProperty{ get; };
    }
    ...
}