Temas avanzados y abreviaturas
Abreviatura
Si usa un tipo con parámetros sin especificar un espacio de nombres, el compilador de MIDL 3.0 lo busca en el Windows. Espacio de nombres Foundation.Collections. En la práctica, esto significa que puede usar la siguiente abreviatura.
Versión corta | Versión larga |
---|---|
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> |
Este mecanismo no se aplica al Windows. Espacio de nombres de Foundation. Por ejemplo, tiene que escribir el nombre completo Windows. Foundation.IAsyncAction.
Sobrecargas
El comportamiento predeterminado de los constructores y métodos sobrecargados es anexar un sufijo numérico a los nombres abi para la segunda sobrecarga y las sobrecargas posteriores dentro de una interfaz.
[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);
}
}
Esta nomenclatura predeterminada no coincide con las directrices de diseño de API recomendadas, por lo que debe reemplazarla por el atributo [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);
}
}
Implementación de una interfaz non-exclusiveto
La derivación de la clase en tiempo de ejecución de una interfaz declara automáticamente los miembros de esa interfaz. No los reclare. Si lo hace, el compilador de MIDL 3.0 asume que quiere implementar un método independiente M() que oculta el de la interfaz.
interface I
{
void M();
}
runtimeclass C : I
{
// Don't redeclare M(). It's automatically inherited from interface I.
// void M();
}
Especificación de la interfaz predeterminada
Si no especifica una interfaz predeterminada, el compilador de MIDL 3.0 elige la primera interfaz de instancia. Para invalidar esta selección, inserte el atributo antes [default]
de la interfaz que desea que sea la interfaz predeterminada.
// 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(...)]
{
...
}
}
Atributos de compatibilidad con versiones anteriores
Si va a convertir MIDL 1.0 o MIDL 2.0 a MIDL 3.0 (vea también Transición a MIDL 3.0 desde MIDLRT clásico), deberá personalizar las cosas que normalmente se generan automáticamente para que los valores generados automáticamente coincidan con los existentes.
- Para especificar el nombre y el UUID de una interfaz, use el
[interface_name("fully.qualified.name", UUID)]
atributo . - Para especificar el nombre y el UUID de una interfaz de generador, use el
[constructor_name("fully.qualified.name", UUID)]
atributo . - Para especificar el nombre y el UUID de una interfaz estática, use el
[static_name("fully.qualified.name", UUID)]
atributo . - Para especificar el nombre de un parámetro de salida, use el
[return_name("name")]
atributo . - Para especificar el nombre de un método, use el
[method_name("name")]
atributo .
La parte "UUID" de los atributos interface_name
, constructor_name
y static_name
es opcional. Si se omite, MIDL generará automáticamente 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();
}
}
El compilador de MIDL 3.0 no le advertirá si se confunde la xxx_name
anotación. Por ejemplo, el ejemplo siguiente se compila sin errores, aunque no haya miembros de instancia para colocar en la interface_name
interfaz . La presencia del atributo interface_name
hace que se genere una interfaz vacía denominada 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);
}
}
Clases vacías
Aunque este uso es algo oscuro, a veces es necesario crear una clase vacía (una clase sin miembros) o una clase de generador vacía. Un ejemplo común de esto se produce con una clase EventArgs . Si se introduce un evento, a veces no es necesario usar argumentos para el evento (el evento que se señala no requiere contexto adicional). Nuestras directrices de diseño de API recomiendan encarecidamente que se proporciona una clase EventArgs , lo que permite a la clase agregar nuevos argumentos de evento en el futuro. Sin embargo, considere esta clase vacía.
runtimeclass MyEventsEventArgs
{
}
Esa clase genera este error.
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' ) ]
Hay varias maneras de corregirlo. La más sencilla es usar el atributo [default_interface]
para expresar que la falta de métodos es intencionada y no un error de creación. Aquí te mostramos cómo hacerlo.
// An empty runtime class needs a [default_interface] tag to indicate that the
// emptiness is intentional.
[default_interface]
runtimeclass MyEventsEventArgs
{
}
Otra manera de corregirlo es con el [interface_name]
atributo . Si MIDL encuentra en una clase sin métodos [interface_name]
normales (o un bloque con control de versiones sin métodos normales), genera una interfaz vacía para ese bloque. De forma similar, [static_name]
si el atributo o [constructor_name]
está presente en una clase o bloque con control de versiones sin constructores estáticos (o ), generará una interfaz vacía para esa interfaz estática o constructor.
Tenga cuidado de no confundir una clase vacía con una clase estática. Puede tener instancias de una clase vacía (aunque no hacen nada), pero no puede tener instancias de una clase estática.
Interfaces vacías
Una interfaz vacía (también denominada interfaz de marcador) debe especificar un explícito [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 se olvida, se produce este error.
error MIDL4010 : [msg]Cannot find the guid attribute of an interface or a delegate. [context]Windows.Widgets.ISomethingMarker
Los UUID generados automáticamente son un hash del contenido de la interfaz, pero si se realizaran para interfaces vacías, todas las interfaces de marcador terminarían con el mismo UUID.
Enumeraciones con ámbito
Si pasa el /enum_class
modificador de comando al compilador midl 3.0, las enumeraciones emitidas por el compilador se declaran como enumeraciones con ámbito (clase enum). No use enumeraciones con ámbito para tipos públicos.
Composición y activación
Para obtener más información sobre las clases que admiten composición, consulta Controles XAML; enlazar a una propiedad de C++/WinRT.
Puede especificar para unsealed runtimeclass
crear una clase que admite composición. Además, puede especificar para indicar unsealed runtimeclass unsealed
si la clase usa agregación COM o activación regular. Esto es significativo para las clases base con constructores públicos.
Interpretación de mensajes de error
error MIDL2025: [msg]syntax error [context]: expecting > or, near ">>"
Si escribe IAsyncOperation<IVectorView<Something>>
, se interpretará >>
como un operador de desplazamiento a la derecha. Para evitarlo, coloque un espacio entre los dos signos mayores que para proporcionar IAsyncOperation<IVectorView<Something> >
.
error MIDL2025: [msg]syntax error [context]: expecting . near ","
Este error se produce si especifica un contrato inexistente, posiblemente debido a un error tipográfico.
[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
Este mensaje de error se genera no solo por la razón del mensaje de error, sino también si intenta colocar los campos de una enumeración en contratos diferentes. Es legal que los campos de una enumeración pertenezcan a versiones diferentes del mismo contrato, pero no pueden estar en contratos completamente diferentes.
error MIDL5161: [msg]Invalid method parameter name [context]: Parameter 'result' (or 'operation' or 'value')
Los nombres de result
parámetro y operation
se reservan en métodos. El nombre del parámetro value
está reservado en constructores.
error MIDL5023: [msg]the arguments to the parameterized interface are not valid
Compruebe que ha escrito correctamente el nombre de la interfaz.
No mezcle MIDL 2.0 y MIDL 3.0 dentro de una sola interfaz
Cada interfaz y clase en tiempo de ejecución deben ser completamente MIDL 2.0 o completamente MIDL 3.0. Es legal hacer referencia a una interfaz MIDL 3.0 desde una clase en tiempo de ejecución MIDL 2.0.
Si intenta mezclar MIDL 2.0 y MIDL 3.0, el compilador trata toda la entidad como MIDL 2.0, lo que produce errores del compilador. Puede encontrarse con este problema si usa accidentalmente la sintaxis midl 2.0 cuando se pretende usar 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.
};
Delegados que devuelven HRESULT
Un delegado que devuelve un valor HRESULT es ambiguo. Podría ser una declaración clásica (anterior a MIDL 3.0) de un delegado que devuelve nominalmente void (donde se usa HRESULT para propagar una excepción) o podría ser una declaración moderna (MIDL 3.0) de un delegado que devuelve nominalmente un HRESULT.
El compilador resuelve la ambigüedad observando otras partes de la declaración. Por ejemplo, si los parámetros se declaran con sintaxis clásica, se supone que la declaración es clásica. Si los parámetros se declaran con sintaxis moderna, se supone que la declaración es moderna.
delegate HRESULT AmbiguousDelegate(INT32 value, RuntimeClassName* r);
- Los parámetros usan la sintaxis clásica, por lo que se supone que se trata de una declaración clásica.
- El equivalente moderno es
delegate void AmbiguousDelegate(Int32 value, RuntimeClassName r);
.
delegate HRESULT AmbiguousDelegate(Int32 value, RuntimeClassName r);
- Los parámetros usan la sintaxis moderna, por lo que se supone que se trata de una declaración moderna.
- El equivalente clásico es
delegate HRESULT AmbiguousDelegate(Int32 value, RuntimeClassName* r, [out, retval] HRESULT* result);
.
A veces, la lista de parámetros no es suficiente para resolver la ambigüedad. Por ejemplo, una lista de parámetros vacía o una lista de parámetros que solo consta de enumeraciones es legal en la sintaxis clásica y moderna. En tales casos, el compilador de MIDL 3.0 tiene como valor predeterminado el clásico.
delegate HRESULT AmbiguousDelegate(MyEnum e);
- Se interpreta como un delegado clásico, donde el delegado devuelve nominalmente void y HRESULT es para propagar una excepción.
- Si realmente quisiera un delegado que devolvía un valor HRESULT, debe usar la sintaxis clásica:
delegate HRESULT AmbiguousDelegate(MyEnum e, [out, retval] HRESULT* result);
.
Afortunadamente, es poco frecuente tener un delegado que devuelva nominalmente HRESULT.
Parámetros de salida en JavaScript y Visual Basic
Consulte Parámetros para obtener información en segundo plano sobre los parámetros de salida.
JavaScript proyecta un método con un parámetro out
de forma diferente a la mayoría de los lenguajes. Si el tipo de valor devuelto de un método es void y tiene out
un único parámetro, out
el método devuelve el parámetro . De lo contrario, el método devuelve un solo objeto; ese objeto tiene una propiedad para cada parámetro out
, más otra propiedad para el valor devuelto (si no es void). En el ejemplo siguiente, el objeto de JavaScript devuelto por la llamada al método tiene una propiedad denominada result y otra propiedad denominada remainder.
runtimeclass Test
{
static void Divide(Int32 x, Int32 y, out Int32 result, out Int32 remainder);
}
Visual Basic no admite parámetros out
-only. Un método con out
parámetros se trata Visual Basic como si fuera ByRef
.