Topik tingkat lanjut, dan singkatan

Pintasan

Jika Anda menggunakan jenis berparameter tanpa menentukan namespace, pengkompilasi MIDL 3.0 mencarinya di namespace Windows.Foundation.Collections. Dalam praktiknya, itu berarti Anda dapat menggunakan singkatan berikut.

Versi pendek Versi panjang
IIterable<T> Windows.Foundation.Collections.IIterable<T>
IIterator<T> Windows.Foundation.Collections.IIterator<T>
IKeyValuePair<K, V> Windows.Foundation.Collections.IKeyValuePair<K, V>
IMap<K, V> Windows.Foundation.Collections.IMap<K, V>
IMapChangedEventArgs<K> Windows.Foundation.Collections.IMapChangedEventArgs<K>
IMapView<K, V> Windows.Foundation.Collections.IMapView<K, V>
IObservableMap<K, V> Windows.Foundation.Collections.IObservableMap<K, V>
IObservableVector<T> Windows.Foundation.Collections.IObservableVector<T>
IVector<T> Windows.Foundation.Collections.IVector<T>
IVectorView<T> Windows.Foundation.Collections.IVectorView<T>
MapChangedEventHandler<K, V> Windows.Foundation.Collections.MapChangedEventHandler<K, V>
VectorChangedEventHandler<T> Windows.Foundation.Collections.VectorChangedEventHandler<T>

Mekanisme ini tidak berlaku untuk namespace Windows.Foundation . Misalnya, Anda harus menulis nama lengkap Windows.Foundation.IAsyncAction.

Overload

Perilaku default untuk metode dan konstruktor yang kelebihan beban adalah menambahkan akhiran numerik ke nama ABI untuk kelebihan beban kedua dan berikutnya dalam antarmuka.

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

Penamaan default ini tidak cocok dengan panduan desain API yang direkomendasikan, jadi ganti dengan atribut [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);
    }
}

Menerapkan antarmuka non-eksklusif ke

Mengambil kelas runtime Anda dari antarmuka secara otomatis mendeklarasikan anggota antarmuka tersebut. Jangan mendeklarasi ulang mereka. Jika Anda melakukannya, pengkompilasi MIDL 3.0 mengasumsikan bahwa Anda ingin menerapkan metode terpisah M() yang menyembunyikan metode dari antarmuka.

interface I
{
    void M();
}

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

Tentukan antarmuka default

Jika Anda tidak menentukan antarmuka default, pengkompilasi MIDL 3.0 memilih antarmuka instans pertama. Untuk mengambil alih pilihan ini, sisipkan atribut [default] sebelum antarmuka yang Anda inginkan menjadi antarmuka 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(...)]
    {
        ...
    }
}

Atribut kompatibilitas mundur

Jika Anda mengonversi MIDL 1.0 atau MIDL 2.0 ke MIDL 3.0 (juga lihat Transisi ke MIDL 3.0 dari MIDLRT klasik), maka Anda harus menyesuaikan hal-hal yang biasanya dibuat secara otomatis sehingga nilai yang dibuat secara otomatis cocok dengan yang ada.

  • Untuk menentukan nama dan UUID antarmuka, gunakan [interface_name("fully.qualified.name", UUID)] atribut .
  • Untuk menentukan nama dan UUID antarmuka pabrik, gunakan [constructor_name("fully.qualified.name", UUID)] atribut .
  • Untuk menentukan nama dan UUID antarmuka statis, gunakan [static_name("fully.qualified.name", UUID)] atribut .
  • Untuk menentukan nama parameter output, gunakan [return_name("name")]atribut .
  • Untuk menentukan nama metode, gunakan [method_name("name")] atribut .

Bagian "UUID" dari interface_nameatribut , constructor_name, dan static_name bersifat opsional. Jika dihilangkan, MIDL akan membuat IID secara otomatis.

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

Pengompilasi MIDL 3.0 tidak akan memperingatkan Anda jika Anda bingung dengan anotasi Anda xxx_name . Misalnya, contoh berikut mengkompilasi tanpa kesalahan, meskipun tidak ada anggota instans untuk dimasukkan ke interface_name dalam antarmuka. Kehadiran interface_name atribut menyebabkan antarmuka kosong bernama ISampleFactory2 dihasilkan.

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

Kelas kosong

Meskipun penggunaan ini agak tidak jelas, terkadang perlu untuk menulis kelas kosong (kelas tanpa anggota), atau kelas pabrik kosong. Contoh umum ini terjadi dengan kelas EventArgs . Jika peristiwa diperkenalkan, terkadang tidak perlu argumen ke peristiwa (peristiwa yang diberi sinyal tidak memerlukan konteks tambahan). Panduan desain API kami sangat merekomendasikan agar kelas EventArgs disediakan, memungkinkan kelas untuk menambahkan argumen peristiwa baru di masa mendatang. Namun, pertimbangkan kelas kosong ini.

runtimeclass MyEventsEventArgs
{
}

Kelas itu menghasilkan kesalahan ini.

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

Ada beberapa cara untuk memperbaikinya. Yang paling sederhana adalah menggunakan [default_interface] atribut untuk mengekspresikan bahwa kurangnya metode disengaja, dan bukan kesalahan penulisan. Berikut cara melakukannya.

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

Cara lain untuk memperbaikinya adalah dengan [interface_name] atribut . Jika MIDL menemukan [interface_name] pada kelas tanpa metode normal (atau blok versi tanpa metode normal), maka ia menghasilkan antarmuka kosong untuk blok tersebut. Demikian pula, jika [static_name] atribut atau [constructor_name] ada pada blok kelas atau versi tanpa statis (atau konstruktor), maka itu akan menghasilkan antarmuka kosong untuk antarmuka statis atau konstruktor tersebut.

Berhati-hatilah untuk tidak membingungkan kelas kosong dengan kelas statis. Anda dapat memiliki instans kelas kosong (meskipun tidak melakukan apa pun), tetapi Anda tidak dapat memiliki instans kelas statis.

Antarmuka kosong

Antarmuka kosong (juga disebut antarmuka penanda) harus menentukan eksplisit [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
{
}

Jika Anda lupa, maka kesalahan ini dihasilkan.

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

UUID yang dibuat secara otomatis adalah hash konten antarmuka, tetapi jika itu dilakukan untuk antarmuka kosong, semua antarmuka penanda akan berakhir dengan UUID yang sama.

Enum terlingkup

Jika Anda meneruskan /enum_class sakelar perintah ke pengkompilasi MIDL 3.0, maka enumerasi yang dipancarkan oleh kompilator dinyatakan sebagai enum terlingkup (kelas enum). Jangan gunakan enum terlingkup untuk jenis publik.

Komposisi dan aktivasi

Untuk informasi selengkapnya tentang kelas yang dapat dikomposisi , lihat kontrol XAML; ikat ke properti C++/WinRT.

Anda dapat menentukan unsealed runtimeclass untuk membuat kelas yang dapat dikomposiskan. Selain itu, Anda dapat menentukan unsealed runtimeclass unsealed untuk menunjukkan apakah kelas menggunakan agregasi COM, atau aktivasi reguler. Ini signifikan untuk kelas dasar dengan konstruktor publik.

Menginterpretasikan pesan kesalahan

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

Jika Anda menulis IAsyncOperation<IVectorView<Something>>, maka >> ditafsirkan sebagai operator shift kanan. Untuk mengatasi hal ini, letakkan ruang di antara dua tanda yang lebih besar untuk diberikan IAsyncOperation<IVectorView<Something> >.

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

Kesalahan ini terjadi jika Anda menentukan kontrak yang tidak ada, mungkin karena kesalahan ketik.

[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

Pesan kesalahan ini dihasilkan tidak hanya karena alasan dalam pesan kesalahan, tetapi juga jika Anda mencoba memasukkan bidang enum ke dalam kontrak yang berbeda. Hukum untuk memiliki bidang enum milik versi yang berbeda dari kontrak yang sama, tetapi mereka tidak dapat berada dalam kontrak yang berbeda sepenuhnya.

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

Nama parameter result dan operation dicadangkan dalam metode. Nama value parameter dicadangkan dalam konstruktor.

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

Periksa apakah Anda mengeja nama antarmuka dengan benar.

Jangan mencampur MIDL 2.0 dan MIDL 3.0 dalam satu antarmuka

Setiap antarmuka dan kelas runtime harus benar-benar MIDL 2.0, atau sepenuhnya MIDL 3.0. Adalah hukum untuk mereferensikan antarmuka MIDL 3.0 dari kelas runtime MIDL 2.0.

Jika Anda mencoba mencampur MIDL 2.0 dan MIDL 3.0, kompilator memperlakukan seluruh entitas sebagai MIDL 2.0, yang menghasilkan kesalahan kompilator. Anda dapat mengalami masalah ini jika Anda tidak sengaja menggunakan sintaks MIDL 2.0 saat Anda berniat menggunakan 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.
};

Delegasi yang mengembalikan HRESULT

Delegasi yang mengembalikan HRESULT bersifat ambigu. Ini bisa menjadi deklarasi klasik (pra-MIDL 3.0) dari delegasi yang secara nominal mengembalikan kekosongan (di mana HRESULT digunakan untuk menyebarkan pengecualian), atau bisa menjadi deklarasi modern (MIDL 3.0) dari delegasi yang secara nominal mengembalikan HRESULT.

Kompilator menyelesaikan ambiguitas dengan melihat bagian lain dari deklarasi. Misalnya, jika parameter dinyatakan dengan sintaks klasik, maka deklarasi diasumsikan klasik. Jika parameter dinyatakan dengan sintaks modern, maka deklarasi diasumsikan modern.

delegate HRESULT AmbiguousDelegate(INT32 value, RuntimeClassName* r);
  • Parameter menggunakan sintaks klasik, jadi ini diasumsikan sebagai deklarasi klasik.
  • Setara modern adalah delegate void AmbiguousDelegate(Int32 value, RuntimeClassName r);.
delegate HRESULT AmbiguousDelegate(Int32 value, RuntimeClassName r);
  • Parameter menggunakan sintaks modern, jadi ini diasumsikan sebagai deklarasi modern.
  • Setara klasik adalah delegate HRESULT AmbiguousDelegate(Int32 value, RuntimeClassName* r, [out, retval] HRESULT* result);.

Terkadang, daftar parameter tidak cukup untuk menyelesaikan ambiguitas. Misalnya, daftar parameter kosong, atau daftar parameter yang hanya terdiri dari enum adalah legal dalam sintaks klasik dan modern. Dalam kasus seperti itu, pengkompilasi MIDL 3.0 default ke klasik.

delegate HRESULT AmbiguousDelegate(MyEnum e);
  • Ditafsirkan sebagai delegasi klasik, di mana delegasi secara nominal mengembalikan kekosongan, dan HRESULT adalah untuk menyebarkan pengecualian.
  • Jika Anda benar-benar menginginkan delegasi yang mengembalikan HRESULT, Anda perlu menggunakan sintaks klasik: delegate HRESULT AmbiguousDelegate(MyEnum e, [out, retval] HRESULT* result);.

Untungnya, jarang memiliki delegasi yang secara nominal mengembalikan HRESULT.

Parameter output di JavaScript dan Visual Basic

Lihat Parameter untuk info latar belakang tentang parameter output.

JavaScript memproyeksikan metode dengan parameter yang out berbeda dari sebagian besar bahasa. Jika jenis pengembalian metode dibatalkan, dan memiliki satu out parameter, maka out parameter dikembalikan oleh metode . Jika tidak, metode mengembalikan satu objek; objek tersebut memiliki properti untuk setiap out parameter, ditambah properti lain untuk nilai yang dikembalikan (jika tidak dibatalkan). Dalam contoh berikut, maka, objek JavaScript yang dikembalikan oleh panggilan metode memiliki properti bernama hasil, dan properti lain bernama sisanya.

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

Visual Basic tidak mendukung out-hanya parameter. Metode dengan out parameter diperlakukan oleh Visual Basic seolah-olah itu ByRef.