Compartilhar via


Tópicos avançados e abreviação

Abreviado

Se você usar um tipo parametrizado sem especificar um namespace, o compilador MIDL 3.0 o procura no Windows. Namespace Foundation.Collections. Na prática, isso significa que você pode usar a seguinte forma resumida.

Versão curta Versão longa
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>

Esse mecanismo não se aplica ao Windows. Namespace de base. Por exemplo, você precisa escrever o nome completo Windows. Foundation.IAsyncAction.

Sobrecargas

O comportamento padrão para métodos sobrecarregados e construtores é anexar um sufixo numérico aos nomes de ABI para a segunda e as sobrecargas subsequentes em uma 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);
    }
}

Essa nomeação padrão não combina com as diretrizes de design de API recomendadas, portanto, substitua-a pelo 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);
    }
}

Implementar uma interface não exclusiva

Derivar sua classe de runtime de uma interface declara automaticamente os membros dessa interface. Não reclare-os. Se você fizer isso, o compilador MIDL 3.0 assumirá que você deseja implementar um método separado M() que oculta o da interface .

interface I
{
    void M();
}

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

Especificar a interface padrão

Se você não especificar uma interface padrão, o compilador MIDL 3.0 escolherá a primeira interface de instância. Para substituir essa seleção, insira o atributo [default] antes da interface que você deseja que seja a interface padrão.

// 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 compatibilidade com backward

Se você estiver convertendo MIDL 1.0 ou MIDL 2.0 para MIDL 3.0 (confira também Transição para MIDL 3.0 do MIDLRT clássico), você precisará personalizar as coisas que normalmente são gerados automaticamente para que os valores gerados automaticamente sejam de acordo com os existentes.

  • Para especificar o nome e o UUID de uma interface, use o [interface_name("fully.qualified.name", UUID)] atributo .
  • Para especificar o nome e o UUID de uma interface de fábrica, use o [constructor_name("fully.qualified.name", UUID)] atributo .
  • Para especificar o nome e o UUID de uma interface estática, use o [static_name("fully.qualified.name", UUID)] atributo .
  • Para especificar o nome de um parâmetro de saída, use o [return_name("name")]atributo .
  • Para especificar o nome de um método, use o [method_name("name")] atributo .

A parte "UUID" dos interface_nameatributos , constructor_namee static_name é opcional. Se omitido, MIDL gerará automaticamente uma 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();
    }
}

O compilador MIDL 3.0 não avisará se você tiver sua xxx_name anotação confusa. Por exemplo, o exemplo a seguir é compilado sem erro, mesmo que não haja membros de instância para colocar na interface_name interface . A presença do atributo interface_name faz com que uma interface vazia chamada ISampleFactory2 seja gerada.

[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 vazias

Embora esse uso seja um pouco obscurecido, às vezes é necessário criar uma classe vazia (uma classe sem membros) ou uma classe de fábrica vazia. Um exemplo comum disso ocorre com uma classe EventArgs . Se um evento for introduzido, às vezes não haverá necessidade de argumentos para o evento (o evento que está sendo sinalizado não requer contexto adicional). Nossas diretrizes de design de API recomendam fortemente que uma classe EventArgs seja fornecida, permitindo que a classe adicione novos argumentos de evento no futuro. No entanto, considere essa classe vazia.

runtimeclass MyEventsEventArgs
{
}

Essa classe produz esse erro.

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

Há várias maneiras de corrigir isso. A mais simples é usar o atributo [default_interface] para expressar que a falta de métodos é intencional e não um erro de autor. Veja a seguir como fazer isso.

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

Outra maneira de corrigir isso é com o [interface_name] atributo . Se MIDL encontrar [interface_name] o em uma classe sem métodos normais (ou um bloco com controle de versão sem métodos normais), ele gerará uma interface vazia para esse bloco. Da mesma forma, [static_name][constructor_name] se o atributo ou estiver presente em uma classe ou bloco com controle de versão sem construtores estáticos (ou ), ele gerará uma interface vazia para essa interface estática ou construtor.

Tenha cuidado para não confundir uma classe vazia com uma classe estática. Você pode ter instâncias de uma classe vazia (embora elas não faça nada), mas não pode ter instâncias de uma classe estática.

Interfaces vazias

Uma interface vazia (também chamada de interface de marcador) deve especificar um 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
{
}

Se você esquecer, esse erro será produzido.

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

UUIDs gerados automaticamente são um hash do conteúdo da interface, mas se isso fosse feito para interfaces vazias, todas as interfaces de marcador terminariam com o mesmo UUID.

Enums com escopo

Se você passar /enum_class a opção de comando para o compilador MIDL 3.0, as enumerações emitidas pelo compilador serão declaradas como enumerações com escopo (classe enum). Não use enums com escopo para tipos públicos.

Composição e ativação

Para obter mais informações sobre classes composáveis , consulte Controles XAML; a bind a uma propriedade C++/WinRT.

Você pode especificar unsealed runtimeclass para criar uma classe composable. Além disso, você pode especificar para unsealed runtimeclass unsealed indicar se a classe usa a agregação COM ou a ativação regular. Isso é significativo para classes base com construtores públicos.

Interpretando mensagens de erro

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

Se você escrever IAsyncOperation<IVectorView<Something>>, o >> será interpretado como um operador de deslocamento para a direita. Para resolver isso, coloque um espaço entre os dois sinais maior que para dar IAsyncOperation<IVectorView<Something> >.

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

Esse erro ocorrerá se você especificar um contrato inexistente, possivelmente devido a um erro de digitação.

[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

Essa mensagem de erro é gerada não apenas pelo motivo na mensagem de erro, mas também se você tentar colocar os campos de uma enum em contratos diferentes. É legal que os campos de uma enum pertençam a versões diferentes do mesmo contrato, mas eles não podem estar totalmente em contratos diferentes.

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

Nomes de result parâmetro operation e são reservados em métodos. O nome do value parâmetro é reservado em construtores.

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

Verifique se você escreveu o nome da interface corretamente.

Não misturar MIDL 2.0 e MIDL 3.0 em uma única interface

Cada interface e classe de runtime devem ser completamente MIDL 2.0 ou completamente MIDL 3.0. É legal referenciar uma interface MIDL 3.0 de uma classe de runtime MIDL 2.0.

Se você tentar misturar MIDL 2.0 e MIDL 3.0, o compilador tratará toda a entidade como MIDL 2.0, o que resulta em erros do compilador. Você poderá ter esse problema se usar acidentalmente a sintaxe MIDL 2.0 quando 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 retornam HRESULT

Um delegado que retorna um HRESULT é ambíguo. Pode ser uma declaração clássica (pré-MIDL 3,0) de um delegado que retorna nominalmente void (onde o HRESULT é usado para propagar uma exceção) ou pode ser uma declaração moderna (MIDL 3,0) de um delegado que retorna nominalmente um HRESULT.

O compilador resolve a ambiguidade examinando outras partes da declaração. Por exemplo, se os parâmetros forem declarados com sintaxe clássica, a declaração será considerada clássica. Se os parâmetros forem declarados com a sintaxe moderna, a declaração será considerada moderna.

delegate HRESULT AmbiguousDelegate(INT32 value, RuntimeClassName* r);
  • Os parâmetros usam sintaxe clássica, portanto, isso é considerado uma declaração clássica.
  • O equivalente moderno é delegate void AmbiguousDelegate(Int32 value, RuntimeClassName r); .
delegate HRESULT AmbiguousDelegate(Int32 value, RuntimeClassName r);
  • Os parâmetros usam sintaxe moderna, portanto, isso é considerado uma declaração moderna.
  • O equivalente clássico é delegate HRESULT AmbiguousDelegate(Int32 value, RuntimeClassName* r, [out, retval] HRESULT* result); .

Às vezes, a lista de parâmetros é insuficiente para resolver a ambiguidade. Por exemplo, uma lista de parâmetros vazias ou uma lista de parâmetros que consiste apenas em enums é legal na sintaxe clássica e moderna. Nesses casos, o compilador MIDL 3,0 usa como padrão o clássico.

delegate HRESULT AmbiguousDelegate(MyEnum e);
  • Interpretado como um delegado clássico, em que o delegado retorna nominalmente void, e o HRESULT é para propagar uma exceção.
  • Se você realmente quisesse um delegado que retornasse um HRESULT, precisará usar a sintaxe clássica: delegate HRESULT AmbiguousDelegate(MyEnum e, [out, retval] HRESULT* result); .

Felizmente, é raro ter um delegado que retorna nominalmente HRESULT.

Parâmetros de saída em JavaScript e Visual Basic

Consulte parâmetros para obter informações de segundo plano sobre parâmetros de saída.

O JavaScript projeta um método com um out parâmetro diferente da maioria dos idiomas. Se o tipo de retorno de um método for void e tiver um único out parâmetro, o out parâmetro será retornado pelo método. Caso contrário, o método retorna um único objeto; esse objeto tem uma propriedade para cada out parâmetro, além de outra propriedade para o valor de retorno (se não for void). No exemplo a seguir, o objeto JavaScript retornado pela chamada de método tem uma propriedade chamada Resulte outra propriedade chamada resto.

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

Visual Basic não dá suporte out a parâmetros somente. um método com out parâmetros é tratado por Visual Basic como se fosse ByRef .