Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Ketika klien COM memanggil objek .NET, bahasa runtime umum membuat objek terkelola dan pembungkus yang dapat dipanggil COM (CCW) untuk objek tersebut. Tidak dapat mereferensikan objek .NET secara langsung, klien COM menggunakan CCW sebagai proksi untuk objek terkelola.
Runtime membuat tepat satu CCW untuk objek terkelola, terlepas dari jumlah klien COM yang meminta layanannya. Seperti yang ditunjukkan oleh ilustrasi berikut, beberapa klien COM dapat menyimpan referensi ke CCW yang mengekspos antarmuka INew. CCW, pada gilirannya, menyimpan satu referensi ke objek terkelola yang mengimplementasikan antarmuka dan merupakan sampah yang dikumpulkan. Klien COM dan .NET dapat membuat permintaan pada objek terkelola yang sama secara bersamaan.
Pembungkus yang dapat dipanggil COM tidak terlihat oleh kelas lain yang berjalan dalam runtime .NET. Tujuan utama mereka adalah untuk mengatur panggilan-panggilan antara kode terkelola dan tidak terkelola; namun, CCW juga mengelola identitas objek dan umur objek dari objek terkelola yang mereka bungkus.
Identitas Objek
Runtime mengalokasikan memori untuk objek .NET dari tumpukan yang dikumpulkan sampahnya, yang memungkinkan runtime untuk memindahkan objek dalam memori seperlunya. Sebaliknya, runtime mengalokasikan memori untuk CCW dari heap yang tidak dikoleksi, sehingga memungkinkan klien COM untuk mereferensi pembungkus secara langsung.
Masa Pakai Objek
Tidak seperti klien .NET yang dibungkusnya, CCW dihitung referensi dengan cara COM tradisional. Ketika jumlah referensi pada CCW mencapai nol, pembungkus merilis referensinya pada objek terkelola. Objek terkelola tanpa referensi yang tersisa dikumpulkan selama siklus pengumpulan sampah berikutnya.
Mensimulasikan antarmuka COM
CCW memaparkan semua antarmuka publik yang dapat dilihat oleh COM, jenis data, dan nilai kembali ke klien COM dengan cara yang konsisten dengan penerapan interaksi berbasis antarmuka COM. Untuk klien COM, memanggil metode pada objek .NET identik dengan memanggil metode pada objek COM.
Untuk membuat pendekatan yang mulus ini, CCW memproduksi antarmuka COM tradisional, seperti IUnknown dan IDispatch. Seperti yang ditunjukkan oleh ilustrasi berikut, CCW mempertahankan satu referensi pada objek .NET yang dibungkusnya. Baik klien COM maupun objek .NET saling berinteraksi melalui konstruksi proksi dan stub dari CCW.
Selain mengekspos antarmuka yang secara eksplisit diimplementasikan oleh kelas di lingkungan terkelola, runtime .NET memasok implementasi antarmuka COM yang tercantum dalam tabel berikut atas nama objek. Kelas .NET dapat mengambil alih perilaku default dengan menyediakan implementasinya sendiri dari antarmuka ini. Namun, runtime selalu menyediakan implementasi untuk antarmuka IUnknown dan IDispatch .
| Antarmuka | Deskripsi |
|---|---|
| IDispatch | Menyediakan mekanisme untuk pengikatan terlambat ke jenis. |
| IErrorInfo | Menyediakan deskripsi tekstual tentang kesalahan, sumbernya, file Bantuan, konteks Bantuan, dan GUID antarmuka yang menentukan kesalahan (selalu GUID_NULL untuk kelas .NET). |
| IProvideClassInfo | Memungkinkan klien COM untuk mendapatkan akses ke antarmuka ITypeInfo yang diimplementasikan oleh kelas terkelola. Mengembalikan COR_E_NOTSUPPORTED di .NET Core untuk tipe yang tidak diimpor dari COM. |
| ISupportErrorInfo | Memungkinkan klien COM untuk menentukan apakah objek terkelola mendukung antarmuka IErrorInfo . Jika demikian, memungkinkan klien untuk mendapatkan penunjuk ke objek pengecualian terbaru. Semua jenis terkelola mendukung antarmuka IErrorInfo . |
| ITypeInfo (hanya .NET Framework) | Menyediakan informasi jenis untuk kelas yang sama persis dengan informasi jenis yang dihasilkan oleh Tlbexp.exe. |
| IUnknown | Menyediakan implementasi standar antarmuka IUnknown yang digunakan klien COM untuk mengelola masa pakai CCW dan menyediakan paksaan tipe. |
Kelas terkelola juga dapat menyediakan antarmuka COM yang dijelaskan dalam tabel berikut.
| Antarmuka | Deskripsi |
|---|---|
| Antarmuka kelas (_classname) | Antarmuka yang diekspos oleh runtime tanpa didefinisikan secara spesifik, yang menampilkan semua antarmuka publik, metode, properti, dan bidang yang secara eksplisit ditampilkan pada objek terkelola. |
| IConnectionPoint dan IConnectionPointContainer | Antarmuka untuk objek yang menjadi sumber peristiwa berbasis delegasi (antarmuka untuk mendaftarkan subscriber peristiwa). |
| IDispatchEx (hanya .NET Framework) | Antarmuka yang disediakan oleh runtime jika kelas mengimplementasikan IExpando. Antarmuka IDispatchEx adalah ekstensi antarmuka IDispatch yang, tidak seperti IDispatch, memungkinkan enumerasi, penambahan, penghapusan, dan panggilan anggota yang peka huruf besar/kecil. |
| IEnumVARIANT | Antarmuka untuk kelas jenis koleksi, yang menghitung objek dalam koleksi jika kelas mengimplementasikan IEnumerable. |
Memperkenalkan antarmuka kelas
Antarmuka kelas, yang tidak secara eksplisit didefinisikan dalam kode terkelola, adalah antarmuka yang mengekspos semua metode publik, properti, bidang, dan peristiwa yang secara eksplisit terekspos pada objek .NET. Antarmuka ini dapat menjadi antarmuka ganda atau khusus pengiriman. Antarmuka kelas menerima nama kelas .NET itu sendiri, didahului oleh garis bawah. Misalnya, untuk kelas Mamalia, antarmuka kelas adalah _Mammal.
Untuk kelas turunan, antarmuka kelas juga mengekspos semua metode publik, properti, dan bidang kelas dasar. Kelas turunan juga mengekspos antarmuka kelas untuk setiap kelas dasar. Misalnya, jika kelas Mammal memperluas kelas MammalSuperclass, yang juga memperluas System.Object, objek .NET mengekspos ke klien COM, tiga antarmuka-antarmuka kelas bernama _Mammal, _MammalSuperclass, dan _Object.
Misalnya, pertimbangkan kelas .NET berikut:
' Applies the ClassInterfaceAttribute to set the interface to dual.
<ClassInterface(ClassInterfaceType.AutoDual)> _
' Implicitly extends System.Object.
Public Class Mammal
Sub Eat()
Sub Breathe()
Sub Sleep()
End Class
// Applies the ClassInterfaceAttribute to set the interface to dual.
[ClassInterface(ClassInterfaceType.AutoDual)]
// Implicitly extends System.Object.
public class Mammal
{
public void Eat() {}
public void Breathe() {}
public void Sleep() {}
}
Klien COM dapat memperoleh pointer ke antarmuka kelas bernama _Mammal. Pada .NET Framework, Anda dapat menggunakan alat Pengekspor Pustaka Jenis (Tlbexp.exe) untuk menghasilkan pustaka jenis yang berisi _Mammal definisi antarmuka. Pengekspor Pustaka Tipe tidak didukung pada .NET Core. Jika kelas Mammal menerapkan satu atau beberapa antarmuka, antarmuka akan muncul di bawah kokelas.
[odl, uuid(…), hidden, dual, nonextensible, oleautomation]
interface _Mammal : IDispatch
{
[id(0x00000000), propget] HRESULT ToString([out, retval] BSTR*
pRetVal);
[id(0x60020001)] HRESULT Equals([in] VARIANT obj, [out, retval]
VARIANT_BOOL* pRetVal);
[id(0x60020002)] HRESULT GetHashCode([out, retval] short* pRetVal);
[id(0x60020003)] HRESULT GetType([out, retval] _Type** pRetVal);
[id(0x6002000d)] HRESULT Eat();
[id(0x6002000e)] HRESULT Breathe();
[id(0x6002000f)] HRESULT Sleep();
}
[uuid(…)]
coclass Mammal
{
[default] interface _Mammal;
}
Menghasilkan antarmuka kelas bersifat opsional. Secara default, interop COM menghasilkan antarmuka khusus pengiriman untuk setiap kelas yang Anda ekspor ke pustaka jenis. Anda dapat mencegah atau mengubah pembuatan otomatis antarmuka ini dengan menerapkannya ke ClassInterfaceAttribute kelas Anda. Meskipun antarmuka kelas dapat memudahkan tugas mengekspos kelas terkelola ke COM, penggunaannya terbatas.
Perhatian
Menggunakan antarmuka kelas, alih-alih secara eksplisit menentukan milik Anda sendiri, dapat mempersulit penerapan versi kelas terkelola Anda di masa mendatang. Harap baca panduan berikut sebelum menggunakan antarmuka kelas.
Tentukan antarmuka eksplisit untuk digunakan klien COM daripada menghasilkan antarmuka kelas.
Karena interop COM menghasilkan antarmuka kelas secara otomatis, perubahan pasca-versi pada kelas Anda dapat mengubah tata letak antarmuka kelas yang diekspos oleh runtime bahasa umum. Karena klien COM biasanya tidak siap untuk menangani perubahan dalam tata letak antarmuka, mereka berhenti jika Anda mengubah tata letak anggota kelas.
Pedoman ini memperkuat gagasan bahwa antarmuka yang diekspos ke klien COM harus tetap tidak dapat diubah. Untuk mengurangi risiko merusak klien COM dengan mengubah struktur antarmuka secara tidak sengaja, isolasi semua perubahan pada kelas dari struktur antarmuka dengan mendefinisikan antarmuka secara eksplisit.
Gunakan ClassInterfaceAttribute untuk melepaskan generasi otomatis antarmuka kelas dan menerapkan antarmuka eksplisit untuk kelas, seperti yang ditunjukkan oleh fragmen kode berikut:
<ClassInterface(ClassInterfaceType.None)>Public Class LoanApp
Implements IExplicit
Sub M() Implements IExplicit.M
…
End Class
[ClassInterface(ClassInterfaceType.None)]
public class LoanApp : IExplicit
{
int IExplicit.M() { return 0; }
}
Nilai ClassInterfaceType.None mencegah antarmuka kelas dihasilkan saat metadata kelas diekspor ke pustaka jenis. Dalam contoh sebelumnya, klien COM hanya dapat mengakses LoanApp kelas melalui IExplicit antarmuka.
Hindari cache pengidentifikasi displai (DispIds)
Menggunakan antarmuka kelas adalah opsi yang dapat diterima untuk klien berskrip, klien Microsoft Visual Basic 6.0, atau klien terikat-akhir yang tidak mem-cache DispId dari anggota antarmuka. DispId mengidentifikasi anggota antarmuka untuk mengaktifkan pengikatan terlambat.
Untuk antarmuka kelas, pembuatan DispIds didasarkan pada posisi anggota di antarmuka. Jika Anda mengubah urutan anggota dan mengekspor kelas ke pustaka jenis, Anda akan mengubah DispId yang dihasilkan di antarmuka kelas.
Untuk menghindari masalah pada klien COM yang diikat secara dinamis saat menggunakan antarmuka kelas, terapkan ClassInterfaceAttribute dengan nilai ClassInterfaceType.AutoDispatch. Nilai ini mengimplementasikan antarmuka kelas khusus pengiriman, tetapi menghilangkan deskripsi antarmuka dari pustaka jenis. Tanpa deskripsi antarmuka, klien tidak dapat men-cache DispIds pada waktu kompilasi. Meskipun ini adalah jenis antarmuka default untuk antarmuka kelas, Anda dapat menerapkan nilai atribut secara eksplisit.
<ClassInterface(ClassInterfaceType.AutoDispatch)> Public Class LoanApp
Implements IAnother
Sub M() Implements IAnother.M
…
End Class
[ClassInterface(ClassInterfaceType.AutoDispatch)]
public class LoanApp
{
public int M() { return 0; }
}
Untuk mendapatkan DispId anggota antarmuka saat runtime, klien COM dapat memanggil IDispatch.GetIdsOfNames. Untuk memanggil metode pada antarmuka, teruskan DispId yang dikembalikan sebagai argumen ke IDispatch.Invoke.
Batasi menggunakan opsi antarmuka ganda untuk antarmuka kelas.
Antarmuka ganda memungkinkan pengikatan awal dan terlambat ke anggota antarmuka oleh klien COM. Selama waktu desain dan pengujian, Anda mungkin merasa berguna untuk mengatur antarmuka kelas ke mode dual. Untuk kelas terkelola (dan kelas dasarnya) yang tidak akan pernah dimodifikasi, opsi ini juga dapat diterima. Dalam semua kasus lain, hindari mengatur antarmuka kelas ke antarmuka dual.
Antarmuka ganda yang dihasilkan secara otomatis mungkin sesuai dalam kasus yang jarang terjadi; namun, lebih sering menyebabkan kompleksitas terkait versi. Misalnya, klien COM yang menggunakan antarmuka kelas kelas turunan dapat dengan mudah rusak dengan perubahan pada kelas dasar. Ketika pihak ketiga menyediakan kelas dasar, tata letak antarmuka kelas berada di luar kendali Anda. Selanjutnya, tidak seperti antarmuka khusus pengiriman, antarmuka ganda (ClassInterfaceType.AutoDual) memberikan deskripsi antarmuka kelas di pustaka jenis yang diekspor. Deskripsi seperti itu mendorong klien yang terlambat terikat untuk men-cache DispIds pada waktu kompilasi.
Pastikan bahwa semua pemberitahuan peristiwa COM terlambat terikat.
Secara default, informasi jenis COM disematkan langsung ke dalam rakitan terkelola, yang menghilangkan kebutuhan akan rakitan interop utama (PIA). Namun, salah satu batasan informasi tipe yang disematkan adalah tidak mendukung pengiriman notifikasi event COM melalui panggilan vtable yang dikaitkan lebih awal, tetapi hanya mendukung panggilan yang dikaitkan lebih lambat IDispatch::Invoke.
Jika aplikasi Anda memerlukan panggilan awal ke metode antarmuka peristiwa COM, Anda dapat mengatur properti Embed Interop Type di Visual Studio ke true, atau menyertakan elemen berikut dalam file proyek Anda:
<EmbedInteropTypes>True</EmbedInteropTypes>