Pemecahan Masalah Interoperabilitas (Visual Basic)
Apabila Anda beroperasi antara COM dan kode terkelola dari .NET Framework, Anda mungkin mengalami satu atau lebih dari masalah umum berikut.
Penyusunan Interop
Terkadang, Anda mungkin harus menggunakan jenis data yang bukan bagian dari .NET Framework. Rakitan interop menangani sebagian besar pekerjaan untuk objek COM, tetapi Anda mungkin harus mengontrol jenis data yang digunakan saat objek terkelola diekspos ke COM. Misalnya, struktur dalam pustaka kelas harus menentukan jenis tidak terkelola BStr
pada string yang dikirim ke objek COM yang dibuat oleh Visual Basic 6.0 dan versi sebelumnya. Dalam kasus tersebut, Anda dapat menggunakan atribut MarshalAsAttribute untuk menyebabkan jenis terkelola diekspos sebagai jenis yang tidak terkelola.
Mengekspor String dengan Panjang Tetap ke Kode Tidak Terkelola
Dalam Visual Basic 6.0 dan versi sebelumnya, string diekspor ke objek COM sebagai urutan byte tanpa karakter terminasi null. Untuk kompatibilitas dengan bahasa lain, Visual Basic .NET menyertakan karakter terminasi saat mengekspor string. Cara terbaik untuk mengatasi ketidaksesuaian ini adalah dengan mengekspor string yang tidak memiliki karakter terminasi sebagai array Byte
atau Char
.
Mengekspor Hierarki Warisan
Hierarki kelas terkelola menjadi rata ketika diekspos sebagai objek COM. Misalnya, jika Anda menentukan kelas dasar dengan anggota, lalu mewarisi kelas dasar di kelas turunan yang diekspos sebagai objek COM, klien yang menggunakan kelas turunan dalam objek COM tidak akan dapat menggunakan anggota yang mendapat warisan. Anggota kelas dasar dapat diakses dari objek COM hanya sebagai instans kelas dasar, dan kemudian hanya jika kelas dasar dibuat sebagai objek COM juga.
Metode Kelebihan Beban
Meskipun Anda dapat membuat metode kelebihan beban dengan Visual Basic, metode tersebut tidak didukung oleh COM. Apabila kelas yang berisi metode kelebihan beban diekspos sebagai objek COM, nama metode baru dihasilkan untuk metode kelebihan beban.
Misalnya, pertimbangkan kelas yang memiliki dua kelebihan beban dari metode Synch
. Apabila kelas diekspos sebagai objek COM, nama metode baru yang dihasilkan bisa jadi Synch
dan Synch_2
.
Penamaan ulang dapat menyebabkan dua masalah bagi konsumen objek COM.
Klien mungkin tidak memperkirakan nama metode yang dihasilkan.
Nama metode yang dihasilkan di kelas yang diekspos sebagai objek COM dapat berubah apabila kelebihan beban baru ditambahkan ke kelas atau kelas dasarnya. Hal ini dapat menyebabkan masalah versi.
Untuk mengatasi kedua masalah tersebut, berikan nama unik pada setiap metode, sebagai ganti dari menggunakan kelebihan beban, apabila Anda mengembangkan objek yang akan diekspos sebagai objek COM.
Penggunaan Objek COM Melalui Rakitan Interop
Anda menggunakan rakitan interop hampir seolah-olah rakitan tersebut adalah pengganti kode terkelola untuk objek COM yang diwakilinya. Namun, karena rakitan interop adalah pembungkus dan bukan objek COM aktual, ada beberapa perbedaan antara penggunaan rakitan interop dan rakitan standar. Area perbedaan ini termasuk paparan kelas, dan jenis data untuk parameter dan nilai pengembalian.
Kelas yang Diekspos sebagai Antarmuka dan Kelas
Tidak seperti kelas dalam rakitan standar, kelas COM diekspos dalam rakitan interop sebagai antarmuka dan kelas yang mewakili kelas COM. Nama antarmuka identik dengan nama kelas COM tersebut. Nama kelas interop sama dengan nama kelas COM asli, tetapi dengan kata "Kelas" yang ditambahkan. Contohnya, Anda memiliki proyek dengan referensi ke rakitan interop untuk objek COM. Jika kelas COM diberi nama MyComClass
, IntelliSense dan Browser Objek menampilkan antarmuka bernama MyComClass
dan kelas bernama MyComClassClass
.
Membuat Instans Kelas .NET Framework
Umumnya, Anda membuat instans kelas .NET Framework menggunakan pernyataan New
dengan nama kelas. Memiliki kelas COM yang diwakili oleh rakitan interop adalah satu kasus di mana Anda dapat menggunakan pernyataan New
dengan antarmuka. Kecuali Anda menggunakan kelas COM dengan pernyataan Inherits
, Anda dapat menggunakan antarmuka persis sebagaimana yang Anda lakukan pada kelas. Kode berikut menunjukkan cara membuat objek Command
dalam proyek yang memiliki referensi ke objek COM Pustaka Objek Data ActiveX Microsoft 2.8:
Dim cmd As New ADODB.Command
Namun, jika Anda menggunakan kelas COM sebagai dasar untuk kelas turunan, Anda harus menggunakan kelas interop yang mewakili kelas COM, seperti dalam kode berikut:
Class DerivedCommand
Inherits ADODB.CommandClass
End Class
Catatan
Rakitan interop secara implisit mengimplementasikan antarmuka yang mewakili kelas COM. Anda tidak boleh mencoba menggunakan pernyataan Implements
untuk mengimplementasikan antarmuka ini atau kesalahan yang akan dihasilkan.
Jenis Data untuk Parameter dan Nilai Pengembalian
Tidak seperti anggota rakitan standar, anggota rakitan interop mungkin memiliki jenis data yang berbeda dari yang digunakan dalam deklarasi objek asli. Meskipun rakitan interop secara implisit mengonversi jenis COM ke jenis runtime bahasa umum yang kompatibel, Anda harus memperhatikan jenis data yang digunakan oleh kedua sisi untuk mencegah kesalahan runtime. Misalnya, dalam objek COM yang dibuat di Visual Basic 6.0 dan versi sebelumnya, yang lebih lama, nilai jenis Integer
mengasumsikan jenis yang setara dari.NET Framework, Short
. Disarankan agar Anda menggunakan Browser Objek untuk memeriksa karakteristik anggota yang diimpor sebelum Anda menggunakannya.
Metode COM tingkat modul
Sebagian besar objek COM digunakan dengan membuat instans kelas COM menggunakan kata kunci New
dan kemudian memanggil metode objek. Satu pengecualian untuk aturan ini melibatkan objek COM yang berisi kelas COM AppObj
atau GlobalMultiUse
. Kelas tersebut menyerupai metode tingkat modul dalam Visual Basic kelas .NET. Visual Basic 6.0 dan versi sebelumnya secara implisit membuat instans objek tersebut untuk Anda saat pertama kali Anda memanggil salah satu metodenya. Misalnya, dalam Visual Basic 6.0 Anda dapat menambahkan referensi ke Pustaka Objek Microsoft DAO 3.6 dan memanggil metode DBEngine
tanpa terlebih dahulu membuat instans:
Dim db As DAO.Database
' Open the database.
Set db = DBEngine.OpenDatabase("C:\nwind.mdb")
' Use the database object.
Visual Basic .NET mengharuskan Anda selalu membuat instans objek COM sebelum Anda dapat menggunakan metodenya. Untuk menggunakan metode ini dalam Visual Basic, deklarasikan variabel kelas yang diinginkan dan gunakan kata kunci baru untuk menetapkan objek pada variabel objek. Kata kunci Shared
dapat digunakan ketika Anda ingin memastikan bahwa hanya satu instans kelas yang dibuat.
' Class level variable.
Shared DBEngine As New DAO.DBEngine
Sub DAOOpenRecordset()
Dim db As DAO.Database
Dim rst As DAO.Recordset
Dim fld As DAO.Field
' Open the database.
db = DBEngine.OpenDatabase("C:\nwind.mdb")
' Open the Recordset.
rst = db.OpenRecordset(
"SELECT * FROM Customers WHERE Region = 'WA'",
DAO.RecordsetTypeEnum.dbOpenForwardOnly,
DAO.RecordsetOptionEnum.dbReadOnly)
' Print the values for the fields in the debug window.
For Each fld In rst.Fields
Debug.WriteLine(fld.Value.ToString & ";")
Next
Debug.WriteLine("")
' Close the Recordset.
rst.Close()
End Sub
Kesalahan Tidak Tertangani dalam Penanganan Aktivitas
Satu masalah interop umum melibatkan kesalahan dalam penanganan aktivitas yang menangani peristiwa yang diangkat oleh objek COM. Kesalahan tersebut diabaikan kecuali Anda secara khusus memeriksa kesalahan menggunakan pernyataan On Error
atau Try...Catch...Finally
. Misalnya, contoh berikut berasal dari proyek .NET Visual Basic yang memiliki referensi ke objek COM Pustaka Objek Data ActiveX Microsoft 2.8.
' To use this example, add a reference to the
' Microsoft ActiveX Data Objects 2.8 Library
' from the COM tab of the project references page.
Dim WithEvents cn As New ADODB.Connection
Sub ADODBConnect()
cn.ConnectionString = "..."
cn.Open()
MsgBox(cn.ConnectionString)
End Sub
Private Sub Form1_Load(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles MyBase.Load
ADODBConnect()
End Sub
Private Sub cn_ConnectComplete(
ByVal pError As ADODB.Error,
ByRef adStatus As ADODB.EventStatusEnum,
ByVal pConnection As ADODB.Connection) Handles cn.ConnectComplete
' This is the event handler for the cn_ConnectComplete event raised
' by the ADODB.Connection object when a database is opened.
Dim x As Integer = 6
Dim y As Integer = 0
Try
x = CInt(x / y) ' Attempt to divide by zero.
' This procedure would fail silently without exception handling.
Catch ex As Exception
MsgBox("There was an error: " & ex.Message)
End Try
End Sub
Contoh ini menimbulkan kesalahan seperti yang diperkirakan. Namun, jika Anda mencoba contoh yang sama tanpa blok Try...Catch...Finally
, kesalahan diabaikan seolah-olah Anda menggunakan pernyataan OnError Resume Next
tersebut. Tanpa penanganan kesalahan, pembagian dengan nol secara diam-diam gagal. Karena kesalahan tersebut tidak pernah menimbulkan kesalahan pengecualian yang tidak tertangani, penting bagi Anda untuk menggunakan beberapa bentuk penanganan pengecualian dalam penanganan aktivitas yang menangani peristiwa dari objek COM.
Memahami kesalahan interop COM
Tanpa penanganan kesalahan, panggilan interop sering menghasilkan kesalahan yang memberikan sedikit informasi. Jika memungkinkan, gunakan penanganan kesalahan terstruktur untuk memberikan informasi lebih lanjut tentang masalah ketika terjadi. Menggunakan penanganan kesalahan terstruktur sangat membantu ketika Anda melakukan debug aplikasi. Contohnya:
Try
' Place call to COM object here.
Catch ex As Exception
' Display information about the failed call.
End Try
Anda dapat menemukan informasi seperti deskripsi kesalahan, HRESULT, dan sumber kesalahan COM dengan memeriksa konten objek pengecualian.
Masalah Kontrol ActiveX
Sebagian besar kontrol ActiveX yang berfungsi dengan Visual Basic 6.0 berfungsi dengan Visual Basic .NET tanpa masalah. Pengecualian utama adalah kontrol kontainer, atau kontrol yang secara visual berisi kontrol lain. Beberapa contoh kontrol lama yang tidak berfungsi dengan benar dengan Visual Studio adalah sebagai berikut:
Kontrol Bingkai Microsoft Forms 2.0
Kontrol Up-Down, juga dikenal sebagai kontrol putar
Kontrol Tab Sheridan
Hanya ada beberapa solusi untuk masalah kontrol ActiveX yang tidak didukung. Anda dapat memigrasikan kontrol yang ada ke Visual Studio jika Anda memiliki kode sumber asli. Jika tidak, Anda dapat memeriksa pada vendor perangkat lunak untuk versi kontrol yang kompatibel dengan NET yang diperbarui untuk menggantikan kontrol ActiveX yang tidak didukung.
Melewati Properti ReadOnly kontrol ByRef
Visual Basic .NET terkadang menimbulkan kesalahan COM seperti, "Kesalahan 0x800A017F CTL_E_SETNOTSUPPORTED", saat Anda meneruskan properti ReadOnly
beberapa kontrol ActiveX yang lebih lama sebagai parameter ByRef
ke prosedur lain. Panggilan prosedur serupa dari Visual Basic 6.0 tidak menimbulkan kesalahan, dan parameter diperlakukan seolah-olah Anda melewatinya berdasarkan nilai. Pesan kesalahan .NET Visual Basic menunjukkan bahwa Anda mencoba mengubah properti yang tidak memiliki prosedur Set
properti.
Jika Anda memiliki akses pada prosedur yang dipanggil, Anda dapat mencegah kesalahan ini dengan menggunakan kata kunci ByVal
untuk mendeklarasikan parameter yang menerima properti ReadOnly
. Contohnya:
Sub ProcessParams(ByVal c As Object)
'Use the arguments here.
End Sub
Jika Anda tidak memiliki akses pada kode sumber untuk prosedur yang dipanggil, Anda dapat memberlakukan properti untuk dilewatkan oleh nilai dengan menambahkan sekumpulan tanda kurung kurawal tambahan di sekitar prosedur panggilan. Misalnya, dalam proyek yang memiliki referensi ke objek COM Pustaka Objek Data ActiveX Microsoft 2.8, Anda dapat menggunakan:
Sub PassByVal(ByVal pError As ADODB.Error)
' The extra set of parentheses around the arguments
' forces them to be passed by value.
ProcessParams((pError.Description))
End Sub
Menyebarkan Rakitan yang Mengekspos Interop
Menyebarkan rakitan yang mengekspos antarmuka COM menghadirkan beberapa tantangan unik. Misalnya, potensi masalah terjadi ketika aplikasi yang terpisah mereferensikan perakitan COM yang sama. Situasi ini umum terjadi ketika versi baru rakitan dipasang dan aplikasi lain masih menggunakan versi rakitan yang lama. Jika Anda menghapus instalan perakitan yang berbagi DLL, Anda bisa dengan tidak sengaja membuat perakitan tersebut tidak tersedia bagi rakitan lainnya.
Untuk menghindari masalah ini, Anda harus memasang rakitan bersama pada Singgahan Perakitan Global (GAC) dan menggunakan MergeModule untuk komponen. Jika Anda tidak dapat memasang aplikasi di GAC, aplikasi harus dipasang pada CommonFilesFolder dalam subdirektori versi khusus.
Rakitan yang tidak dibagikan harus ditempatkan berdampingan pada direktori dengan aplikasi panggilan.