고급 토픽 및 약식

약식

네임스페이스를 지정하지 않고 매개 변수가 있는 형식을 사용하는 경우 MIDL 3.0 컴파일러는 Windows 해당 형식을 찾습니다. Foundation.Collections 네임스페이스입니다. 실제로 다음과 같은 약식으로 사용할 수 있음을 의미합니다.

짧은 버전 긴 버전
IIterable<T> Windows. Foundation.Collections.IIterableT<>
IIteratorT<> Windows. Foundation.Collections.IIteratorT<>
IKeyValuePair<K, 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>

이 메커니즘은 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으로 변환하는 경우( 클래식 MIDLRT에서 MIDL 3.0으로 전환 참조) 자동 생성된 값이 기존 값과 일치하도록 일반적으로 자동 생성된 항목을 사용자 지정해야 합니다.

  • 인터페이스의 이름 및 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_nameconstructor_namestatic_name "UUID" 부분은 선택 사항입니다. 생략하면 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] 일반 메서드(또는 일반 메서드가 없는 버전이 지정된 블록)가 없는 클래스에서 발생하는 경우 해당 블록에 대한 빈 인터페이스를 생성합니다. 마찬가지로, 정적(또는 생성자)이 없는 클래스 또는 버전이 지정된 블록에 특성 [constructor_name] 이 있는 경우 [static_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 컴파일러에 전달하면 컴파일러에서 내보낸 열거형이 범위가 지정된 열거형(열거형 클래스)으로 선언됩니다. public 형식에는 범위가 지정된 열거형을 사용하지 마세요.

컴퍼지션 및 활성화

구성 가능한 클래스에 대한 자세한 내용은 XAML 컨트롤을 참조하세요. C++/WinRT 속성에 바인딩합니다.

구성 가능한 클래스를 만들도록 지정할 unsealed runtimeclass 수 있습니다. 또한 클래스에서 COM 집계를 사용하는지 또는 일반 정품 인증을 사용하는지 여부를 나타내도록 지정할 unsealed runtimeclass unsealed 수 있습니다. 이는 공용 생성자가 있는 기본 클래스에 중요합니다.

오류 메시지 해석

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

매개 변수 이름 resultoperation 메서드에서 예약됩니다. 매개 변수 이름은 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 2.0 런타임 클래스에서 MIDL 3.0 인터페이스를 참조하는 것은 합법적입니다 .

MIDL 2.0과 MIDL 3.0을 혼합하려고 하면 컴파일러는 전체 엔터티를 MIDL 2.0으로 처리하므로 컴파일러 오류가 발생합니다. MIDL 3.0을 사용하려는 경우 실수로 MIDL 2.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를 반환하는 대리자는 모호합니다. 명목상 void( HRESULT 가 예외를 전파하는 데 사용되는 경우)를 반환하는 대리자의 클래식(MIDL 3.0 이전) 선언이거나 명목상 HRESULT를 반환하는 대리자의 최신(MIDL 3.0) 선언일 수 있습니다.

컴파일러는 선언의 다른 부분을 확인하여 모호성을 해결합니다. 예를 들어 매개 변수가 클래식 구문을 사용하여 선언된 경우 선언은 클래식으로 간주됩니다. 매개 변수가 최신 구문으로 선언된 경우 선언은 최신으로 간주됩니다.

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 개체에 명명된 결과 속성과 나머지라는 다른 속성이 있습니다.

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

Visual Basic -only 매개 변수를 지원하지 out않습니다. 매개 변수가 있는 out 메서드는 Visual Basic 처리됩니다ByRef.