Argomenti avanzati e sintassi abbreviata

Sintassi abbreviata

Se si usa un tipo con parametri senza specificare uno spazio dei nomi, il compilatore MIDL 3.0 lo cerca nel Windows. Spazio dei nomi Foundation.Collections. In pratica, ciò significa che è possibile usare la sintassi abbreviata seguente.

Versione breve Versione lunga
IIterable<T> Windows. Foundation.Collections.IIterableT<>
IIteratorT<> Windows. Foundation.Collections.IIteratorT<>
IKeyValuePairK<, V> Windows. Foundation.Collections.IKeyValuePairK<, V>
IMapK<, 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.VectorChangedEventHandlerT<>

Questo meccanismo non si applica al Windows. Spazio dei nomi Foundation. Ad esempio, è necessario scrivere il nome completo Windows. Foundation.IAsyncAction.

Overload

Il comportamento predefinito per i metodi e i costruttori di overload è l'aggiunta di un suffisso numerico ai nomi ABI per il secondo overload e gli overload successivi all'interno di un'interfaccia.

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

Questa denominazione predefinita non corrisponde alle linee guida consigliate per la progettazione delle API, quindi eseguirne l'override con l'attributo [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);
    }
}

Implementare un'interfaccia non esclusiva

Derivando la classe di runtime da un'interfaccia vengono dichiarati automaticamente i membri di tale interfaccia. Non reiclare questi dati. In questo caso, il compilatore MIDL 3.0 presuppone che si voglia implementare un metodo separato M() che nasconde quello dall'interfaccia.

interface I
{
    void M();
}

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

Specificare l'interfaccia predefinita

Se non si specifica un'interfaccia predefinita, il compilatore MIDL 3.0 sceglie l'interfaccia della prima istanza. Per eseguire l'override di questa selezione, inserire l'attributo [default] prima dell'interfaccia che si vuole impostare come interfaccia predefinita.

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

Attributi di compatibilità con le versioni precedenti

Se si sta convertendo MIDL 1.0 o MIDL 2.0 in MIDL 3.0 (vedere anche Transition to MIDL 3.0 from classic MIDLRT (Transizione a MIDL 3.0 dalla versione classica di MIDLRT), sarà necessario personalizzare gli elementi normalmente rigenerati automaticamente in modo che i valori rigenerati automaticamente corrispondano a quelli esistenti.

  • Per specificare il nome e l'UUID di un'interfaccia, usare l'attributo [interface_name("fully.qualified.name", UUID)] .
  • Per specificare il nome e l'UUID di un'interfaccia factory, usare l'attributo [constructor_name("fully.qualified.name", UUID)] .
  • Per specificare il nome e l'UUID di un'interfaccia statica, usare l'attributo [static_name("fully.qualified.name", UUID)] .
  • Per specificare il nome di un parametro di output, usare l'attributo [return_name("name")].
  • Per specificare il nome di un metodo, usare l'attributo [method_name("name")] .

La parte "UUID" degli attributi interface_name, constructor_namee static_name è facoltativa. Se omesso, MIDL genererà automaticamente 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();
    }
}

Il compilatore MIDL 3.0 non genera un avviso se l'annotazione viene confusa xxx_name . Ad esempio, l'esempio seguente viene compilato senza errori, anche se non sono presenti membri di istanza da inserire nell'interfaccia interface_name . La presenza dell'attributo interface_name causa la generazione di un'interfaccia vuota denominata 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);
   }
}

Classi vuote

Anche se questo utilizzo è poco comune, a volte è necessario creare una classe vuota (una classe senza membri) o una classe factory vuota. Un esempio comune si verifica con una classe EventArgs . Se viene introdotto un evento, a volte non sono necessari argomenti per l'evento (l'evento segnalato non richiede contesto aggiuntivo). Le linee guida di progettazione dell'API consigliano vivamente di usare una classe EventArgs , consentendo alla classe di aggiungere nuovi argomenti di evento in futuro. Si consideri tuttavia questa classe vuota.

runtimeclass MyEventsEventArgs
{
}

La classe genera questo errore.

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

Esistono diversi modi per risolvere questo problema. Il più semplice è usare l'attributo [default_interface] per esprimere che la mancanza di metodi è intenzionale e non un errore di creazione. Ecco come farlo.

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

Un altro modo per risolvere questo problema è con l'attributo [interface_name] . Se MIDL rileva in [interface_name] una classe senza metodi normali (o un blocco con versione senza metodi normali), genera un'interfaccia vuota per tale blocco. Analogamente, se [static_name][constructor_name] l'attributo o è presente in una classe o in un blocco con versione senza costruttori (o statici), verrà generata un'interfaccia vuota per tale interfaccia o costruttore statico.

Prestare attenzione a non confondere una classe vuota con una classe statica. È possibile avere istanze di una classe vuota (anche se non ese) ma non è possibile avere istanze di una classe statica.

Interfacce vuote

Un'interfaccia vuota (detta anche interfaccia marcatore) deve specificare un oggetto esplicito [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 si dimentica, viene generato questo errore.

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

Gli UUID rigenerati automaticamente sono un hash del contenuto dell'interfaccia, ma se ciò fosse stato fatto per le interfacce vuote, tutte le interfacce marcatore finirebbero con lo stesso UUID.

Enumerazioni con ambito

Se si passa /enum_class l'opzione del comando al compilatore MIDL 3.0, le enumerazioni generate dal compilatore vengono dichiarate come enumerazioni con ambito (classe enum). Non usare enumerazioni con ambito per i tipi pubblici.

Composizione e attivazione

Per altre info sulle classi componibili , vedi Controlli XAML; binding a una proprietà C++/WinRT.

È possibile specificare unsealed runtimeclass per creare una classe componibile. Inoltre, è possibile specificare per unsealed runtimeclass unsealed indicare se la classe utilizza l'aggregazione COM o l'attivazione regolare. Ciò è significativo per le classi di base con costruttori pubblici.

Interpretazione dei messaggi di errore

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

Se si scrive IAsyncOperation<IVectorView<Something>>, viene interpretato >> come operatore di spostamento a destra. Per risolvere questo problema, inserire uno spazio tra i due segni di maggiore di per fornire IAsyncOperation<IVectorView<Something> >.

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

Questo errore si verifica se si specifica un contratto inesistente, probabilmente a causa di un errore di digitazione.

[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

Questo messaggio di errore viene generato non solo per il motivo nel messaggio di errore, ma anche se si tenta di inserire i campi di un'enumerazione in contratti diversi. È possibile che i campi di un'enumerazione appartengano a versioni diverse dello stesso contratto, ma non possono essere interamente in contratti diversi.

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

I nomi dei result parametri e operation sono riservati nei metodi . Il nome del value parametro è riservato nei costruttori.

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

Verificare che il nome dell'interfaccia sia stato digitato correttamente.

Non combinare MIDL 2.0 e MIDL 3.0 all'interno di una singola interfaccia

Ogni interfaccia e classe di runtime deve essere completamente MIDL 2.0 o completamente MIDL 3.0. È valido fare riferimento a un'interfaccia MIDL 3.0 da una classe di runtime MIDL 2.0.

Se si tenta di combinare MIDL 2.0 e MIDL 3.0, il compilatore considera l'intera entità come MIDL 2.0, causando errori del compilatore. Questo problema può verificarsi se si usa accidentalmente la sintassi MIDL 2.0 quando si intendeva usare 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.
};

Delegati che restituiscono HRESULT

Un delegato che restituisce un HRESULT è ambiguo. Può trattarsi di una dichiarazione classica (precedente a MIDL 3.0) di un delegato che restituisce nominalmente void (dove HRESULT viene usato per propagare un'eccezione) oppure può essere una dichiarazione moderna (MIDL 3.0) di un delegato che restituisce nominalmente un HRESULT.

Il compilatore risolve l'ambiguità esaminando altre parti della dichiarazione. Ad esempio, se i parametri vengono dichiarati con la sintassi classica, si presuppone che la dichiarazione sia classica. Se i parametri vengono dichiarati con una sintassi moderna, si presuppone che la dichiarazione sia moderna.

delegate HRESULT AmbiguousDelegate(INT32 value, RuntimeClassName* r);
  • I parametri usano la sintassi classica, quindi si presuppone che si tratta di una dichiarazione classica.
  • L'equivalente moderno è delegate void AmbiguousDelegate(Int32 value, RuntimeClassName r);.
delegate HRESULT AmbiguousDelegate(Int32 value, RuntimeClassName r);
  • I parametri usano una sintassi moderna, quindi si presuppone che si tratta di una dichiarazione moderna.
  • L'equivalente classico è delegate HRESULT AmbiguousDelegate(Int32 value, RuntimeClassName* r, [out, retval] HRESULT* result);.

In alcuni casi, l'elenco di parametri non è sufficiente per risolvere l'ambiguità. Ad esempio, un elenco di parametri vuoto o un elenco di parametri costituito solo da enumerazioni è valido sia nella sintassi classica che in quella moderna. In questi casi, il compilatore MIDL 3.0 viene utilizzato per impostazione predefinita come versione classica.

delegate HRESULT AmbiguousDelegate(MyEnum e);
  • Interpretato come un delegato classico, in cui il delegato restituisce nominalmente void e HRESULT è per la propagazione di un'eccezione.
  • Se si vuole davvero un delegato che ha restituito un HRESULT, è necessario usare la sintassi classica: delegate HRESULT AmbiguousDelegate(MyEnum e, [out, retval] HRESULT* result);.

Fortunatamente, è raro avere un delegato che restituisce nominalmente HRESULT.

Parametri di output in JavaScript e Visual Basic

Per informazioni di base sui parametri di output, vedere Parametri.

JavaScript proietta un metodo con un parametro out in modo diverso rispetto alla maggior parte dei linguaggi. Se il tipo restituito di un metodo è void e ha un out singolo parametro, out il parametro viene restituito dal metodo . In caso contrario, il metodo restituisce un singolo oggetto . tale oggetto dispone di una proprietà per ogni out parametro, più un'altra proprietà per il valore restituito (se non void). Nell'esempio seguente, quindi, l'oggetto JavaScript restituito dalla chiamata al metodo ha una proprietà denominata result e un'altra proprietà denominata remainder.

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

Visual Basic non supporta parametri out-only. Un metodo con out parametri viene considerato Visual Basic come se fosse ByRef.