Поделиться через


Дополнительные разделы и сокращения

Сокращение

Если вы используете параметризованный тип без указания пространства имен, компилятор MIDL 3,0 ищет его в Windows. Пространство имен Foundation. Collections. На практике это означает, что можно использовать следующую краткую форму.

Краткая версия Длинная версия
IIterable<T> Windows. Foundation. Collections. Иитерабле < T>
Иитератор < T> Windows. Foundation. Collections. Иитератор < T>
IKeyValuePair < K, V> Windows. Foundation. Collections. IKeyValuePair < K, V>
IMap<K, V> Windows. Foundation. Collections. IMap < K, V>
Имапчанжедевентаргс < р> Windows. Foundation. Collections. Имапчанжедевентаргс < K>
IMapView<K, V> Windows. Foundation. Collections. IMapView < K, V>
IObservableMap < K, V> Windows. Foundation. Collections. IObservableMap < K, V>
Иобсерваблевектор < T> Windows. Foundation. Collections. Иобсерваблевектор < T>
IVector<T> Windows. Foundation. Collections. IVector < T>
IVectorView<T> Windows. Foundation. Collections. IVectorView < T>
Мапчанжедевенсандлер < K, V> Windows. Foundation. Collections. Мапчанжедевенсандлер < K, V>
VectorChangedEventHandler < T> Windows.Foundation.Collections.VectorChangedEventHandler<T>

Этот механизм не применяется к Windows. Пространство имен Foundation. Например, необходимо написать полное имя Windows. Foundation. IAsyncAction.

Перегрузки

Поведением по умолчанию для перегруженных методов и конструкторов является Добавление числового суффикса к именам ABI для второй и последующих перегрузок в интерфейсе.

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

Такое именование по умолчанию не соответствует рекомендациям по проектированию API, поэтому переопределите его атрибутом [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);
    }
}

Реализация интерфейса, не являющегося ексклусивето

При наследовании класса среды выполнения из интерфейса автоматически объявляются члены этого интерфейса. Не переобъявляйте их повторно. В противном случае компилятор MIDL 3,0 предполагает, что необходимо реализовать отдельный метод M () , который скрывает объект из интерфейса.

interface I
{
    void M();
}

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

Укажите интерфейс по умолчанию

Если не указать интерфейс по умолчанию, компилятор MIDL 3,0 выбирает первый интерфейс экземпляра. Чтобы переопределить этот выбор, вставьте атрибут [default] перед интерфейсом, который должен быть интерфейсом по умолчанию.

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

Атрибуты обратной совместимости

Если вы преобразуете MIDL 1,0 или MIDL 2,0 в MIDL 3,0 (см. также Переход на midl 3,0 из классической MIDLRT), вам потребуется настроить объекты, которые обычно формируются автоматически, чтобы автоматически сформированные значения совпадали с существующими.

  • Чтобы указать имя и UUID интерфейса, используйте [interface_name("fully.qualified.name", UUID)] атрибут.
  • Чтобы указать имя и UUID интерфейса фабрики, используйте [constructor_name("fully.qualified.name", UUID)] атрибут.
  • Чтобы указать имя и UUID статического интерфейса, используйте [static_name("fully.qualified.name", UUID)] атрибут.
  • Чтобы указать имя выходного параметра, используйте [return_name("name")] атрибут.
  • Чтобы указать имя метода, используйте [method_name("name")] атрибут.

Часть interface_name "UUID" атрибутов, constructor_name и static_name является необязательной. Если этот параметр не указан, MIDL автоматически создает идентификатор 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();
    }
}

Компилятор MIDL 3,0 не выдаст предупреждение, если вы получите разобраться в xxx_name аннотации. Например, следующий пример компилируется без ошибок, даже если нет членов экземпляра для размещения в interface_name интерфейсе. Наличие interface_name атрибута приводит к созданию пустого интерфейса с именем 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);
   }
}

Пустые классы

Хотя это использование несколько незаметно, иногда бывает необходимо создать пустой класс (класс без членов) или пустой класс фабрики. Распространенный пример такого события — класс EventArgs . Если событие введено, иногда нет необходимости в аргументах для события (для события, для которого не требуется дополнительный контекст). Наши рекомендации по проектированию API настоятельно рекомендуют обеспечить предоставление класса EventArgs , позволяя классу добавлять новые аргументы событий в будущем. Однако рассмотрим этот пустой класс.

runtimeclass MyEventsEventArgs
{
}

Этот класс вызывает эту ошибку.

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

Это можно исправить несколькими способами. Самый простой — использовать [default_interface] атрибут, чтобы выразить, что отсутствие методов является намеренным, а не ошибкой разработки. Вот как это сделать.

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

Другой способ исправить это с помощью [interface_name] атрибута. Если MIDL встречает [interface_name] в классе без обычных методов (или блока с версией без обычных методов), то для этого блока создается пустой интерфейс. Аналогично, если [static_name] атрибут или [constructor_name] имеется в классе или блоке с версией без статических (или конструкторов), то он создаст пустой интерфейс для этого статического интерфейса или конструктора.

Будьте осторожны, чтобы не путать пустой класс со статическим классом. Можно иметь экземпляры пустого класса (хотя они ничего не делают), но экземпляры статического класса использовать нельзя.

Пустые интерфейсы

Пустой интерфейс (также называемый интерфейсом маркера) должен задавать явный [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
{
}

Если вы забыли, то эта ошибка будет вызвана.

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

Автоматически сформированные UUID — это хэш содержимого интерфейса, но если это было сделано для пустых интерфейсов, все интерфейсы маркера будут иметь одинаковый UUID.

Перечислений с заданной областью

Если передать /enum_class Переключение команды в КОМПИЛЯТОР MIDL 3,0, то перечисления, созданные компилятором, объявляются в виде перечислений с областью действия (Класс Enum). Не используйте перечисление с заданной областью для открытых типов.

Композиция и активация

Дополнительные сведения о классах, допускающих композицию , см. в разделе элементы управления XAML; привязка к свойству/WinRT C++.

Можно указать unsealed runtimeclass , чтобы создать класс, допускающий композицию. Кроме того, можно указать unsealed runtimeclass unsealed , использует ли класс агрегирование com или обычную активацию. Это важно для базовых классов с открытыми конструкторами.

Интерпретация сообщений об ошибках

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

Если вы пишете IAsyncOperation<IVectorView<Something>> , то объект >> интерпретируется как оператор сдвига вправо. Чтобы обойти это, разместите пробел между двумя знаками «больше», которые нужно дать IAsyncOperation<IVectorView<Something> > .

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

Эта ошибка возникает, если указать несуществующий контракт, возможно, из-за опечатки.

[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

Это сообщение об ошибке создается не только по причине сообщения об ошибке, но и при попытке разместить поля перечисления в разных контрактах. Допускается, чтобы поля перечисления применялись к разным версиям одного и того же контракта, но не могут быть в разных контрактах полностью.

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

Имена result параметров и operation зарезервированы в методах. Имя value параметра зарезервировано в конструкторах.

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

Проверьте правильность написания имени интерфейса.

Не смешивать MIDL 2,0 и MIDL 3,0 в одном интерфейсе

Каждый интерфейс и класс среды выполнения должны быть либо полностью MIDL 2,0, либо полностью MIDL 3,0. Допустимо ссылаться на интерфейс MIDL 3,0 из класса среды выполнения MIDL 2,0.

При попытке смешивать MIDL 2,0 и MIDL 3,0 компилятор считает всю сущность в виде MIDL 2,0, что приводит к ошибкам компилятора. Вы можете столкнуться с этой проблемой, если вы случайно используете синтаксис MIDL 2,0, когда планируется использовать 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.
};

Делегаты, возвращающие HRESULT

Делегат, возвращающий значение HRESULT , является неоднозначным. Это классическое объявление (pre-MIDL 3,0) делегата, который номинально возвращает значение void (где значение HRESULT используется для распространения исключения) или как современное (MIDL 3,0) делегата, который номинально возвращает значение HRESULT.

Компилятор разрешает неоднозначность, просматривая другие части объявления. Например, если параметры объявляются с помощью классического синтаксиса, то предполагается, что объявление является классическим. Если параметры объявляются с помощью современного синтаксиса, то предполагается, что объявление является современным.

delegate HRESULT AmbiguousDelegate(INT32 value, RuntimeClassName* r);
  • Параметры используют классический синтаксис, поэтому предполагается, что это классический объявление.
  • Современный эквивалент имеет значение delegate void AmbiguousDelegate(Int32 value, RuntimeClassName r); .
delegate HRESULT AmbiguousDelegate(Int32 value, RuntimeClassName r);
  • Параметры используют современный синтаксис, поэтому предполагается, что это современное объявление.
  • Классический эквивалент — delegate HRESULT AmbiguousDelegate(Int32 value, RuntimeClassName* r, [out, retval] HRESULT* result); .

Иногда список параметров недостаточен для устранения неоднозначности. Например, список пустых параметров или список параметров, состоящий только из перечислений, является допустимым как в классическом, так и в современном синтаксисе. В таких случаях компилятор MIDL 3,0 по умолчанию имеет классический вид.

delegate HRESULT AmbiguousDelegate(MyEnum e);
  • Интерпретируется как классический делегат, где делегат номинально возвращает значение void, а значение HRESULT — для распространения исключения.
  • Если вам действительно нужен делегат, возвращающий HRESULT, необходимо использовать классический синтаксис: delegate HRESULT AmbiguousDelegate(MyEnum e, [out, retval] HRESULT* result); .

К счастью, очень редко приходится иметь делегат, который номинально возвращает HRESULT.

Выходные параметры в JavaScript и Visual Basic

Общие сведения о выходных параметрах см. в разделе Параметры .

JavaScript в проектах метод с out параметром отличается от большинства языков. Если возвращаемый тип метода имеет значение void и имеет один out параметр, то этот out параметр возвращается методом. В противном случае метод возвращает один объект. у этого объекта есть свойство для каждого out параметра, а также другое свойство для возвращаемого значения (если не void). В следующем примере объект JavaScript, возвращаемый вызовом метода, имеет свойство resultи другое свойство с именем остаток.

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

Visual Basic не поддерживает out параметры. метод с out параметрами обрабатывается Visual Basic как если бы он был ByRef .