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


Устранение неполадок взаимодействия (Visual Basic)

При взаимодействии между COM и управляемым кодом платформа .NET Framework может возникнуть одна или несколько из следующих распространенных проблем.

Маршалинг взаимодействия

Иногда может потребоваться использовать типы данных, которые не являются частью платформа .NET Framework. Сборки взаимодействия выполняют большую часть работы для COM-объектов, но может потребоваться управлять типами данных, которые используются при доступе управляемых объектов к COM. Например, структуры в библиотеках классов должны указывать неуправляемый BStr тип в строках, отправляемых в COM-объекты, созданные Visual Basic 6.0 и более ранними версиями. В таких случаях атрибут можно использовать MarshalAsAttribute для предоставления управляемым типам неуправляемых типов.

Экспорт строк Fixed-Length в неуправляемый код

В Visual Basic 6.0 и более ранних версиях строки экспортируются в COM-объекты в виде последовательностей байтов без символа завершения null. Для совместимости с другими языками Visual Basic .NET включает символ завершения при экспорте строк. Лучший способ устранить эту несовместимость — экспортировать строки, в которые отсутствует символ завершения, в виде массивов Byte или Char.

Экспорт иерархий наследования

Иерархии управляемых классов удаляются в плоскую структуру при их представлении в виде COM-объектов. Например, если определить базовый класс с помощью члена, а затем наследовать базовый класс в производном классе, который предоставляется в виде COM-объекта, клиенты, использующие производный класс в COM-объекте, не смогут использовать наследуемые члены. Доступ к членам базового класса из COM-объектов можно получить только как экземпляры базового класса, а затем только в том случае, если базовый класс также создан как COM-объект.

Перегруженные методы

Хотя вы можете создавать перегруженные методы с помощью Visual Basic, они не поддерживаются COM. Когда класс, содержащий перегруженные методы, предоставляется в виде COM-объекта, для перегруженных методов создаются новые имена методов.

Например, рассмотрим класс с двумя Synch перегрузками метода . Если класс предоставляется в виде COM-объекта, новые созданные имена методов могут быть Synch и Synch_2.

Переименование может вызвать две проблемы для потребителей COM-объекта.

  1. Клиенты могут не ожидать созданных имен методов.

  2. Созданные имена методов в классе, предоставленном в виде COM-объекта, могут изменяться при добавлении новых перегрузок в класс или его базовый класс. Это может привести к проблемам управления версиями.

Чтобы решить обе проблемы, присвойте каждому методу уникальное имя вместо использования перегрузки при разработке объектов, которые будут представлены в виде COM-объектов.

Использование COM-объектов с помощью сборок взаимодействия

Сборки взаимодействия используются почти так же, как если бы они заменяли управляемый код для com-объектов, которые они представляют. Однако поскольку они являются оболочками, а не фактическими COM-объектами, существуют некоторые различия между использованием сборок взаимодействия и стандартных сборок. Эти области различия включают в себя подверженность классов и типов данных для параметров и возвращаемых значений.

Классы, предоставляемые как интерфейсы и классы

В отличие от классов в стандартных сборках, COM-классы предоставляются в сборках взаимодействия как интерфейс и класс, представляющий com-класс. Имя интерфейса идентично имени класса COM. Имя класса взаимодействия совпадает с именем исходного КЛАССА COM, но с добавлением слова "Класс". Например, предположим, что у вас есть проект со ссылкой на сборку взаимодействия для COM-объекта. Если com-класс имеет имя MyComClass, IntelliSense и обозреватель объектов отображают интерфейс с именем MyComClass и класс с именем MyComClassClass.

Создание экземпляров класса платформа .NET Framework

Как правило, экземпляр класса платформа .NET Framework создается с помощью New оператора с именем класса. Наличие COM-класса, представленного сборкой взаимодействия, — это тот случай, в котором можно использовать New оператор с интерфейсом . Если вы не используете COM-класс с оператором Inherits , интерфейс можно использовать так же, как класс. В следующем коде показано, как создать Command объект в проекте со ссылкой на COM-объект библиотеки Microsoft ActiveX Data Objects 2.8:

Dim cmd As New ADODB.Command

Однако если в качестве основы для производного класса используется COM-класс, необходимо использовать класс взаимодействия, представляющий COM-класс, как показано в следующем коде:

Class DerivedCommand
    Inherits ADODB.CommandClass
End Class

Примечание

Сборки взаимодействия неявно реализуют интерфейсы, представляющие COM-классы. Не следует пытаться использовать Implements оператор для реализации этих интерфейсов, иначе произойдет ошибка.

Типы данных для параметров и возвращаемых значений

В отличие от членов стандартных сборок, члены сборки взаимодействия могут иметь типы данных, отличающиеся от тех, которые использовались в объявлении исходного объекта. Хотя сборки взаимодействия неявно преобразуют типы COM в совместимые типы среды CLR, следует обратить внимание на типы данных, используемые обеими сторонами для предотвращения ошибок среды выполнения. Например, в COM-объектах, созданных в Visual Basic 6.0 и более ранних версиях, значения типа Integer предполагают платформа .NET Framework эквивалентного типа , Short. Рекомендуется использовать обозреватель объектов для проверки характеристик импортированных элементов перед их использованием.

Com-методы уровня модуля

Большинство COM-объектов используются путем создания экземпляра COM-класса с помощью New ключевое слово и последующего вызова методов объекта . Одним из исключений из этого правила являются COM-объекты, содержащие AppObj классы или GlobalMultiUse COM. Такие классы похожи на методы уровня модуля в классах Visual Basic .NET. Visual Basic 6.0 и более ранние версии неявно создают экземпляры таких объектов при первом вызове одного из их методов. Например, в Visual Basic 6.0 можно добавить ссылку на библиотеку объектов Microsoft DAO 3.6 и вызвать DBEngine метод без предварительного создания экземпляра:

Dim db As DAO.Database  
' Open the database.  
Set db = DBEngine.OpenDatabase("C:\nwind.mdb")  
' Use the database object.  

Visual Basic .NET требует, чтобы вы всегда создавали экземпляры COM-объектов, прежде чем использовать их методы. Чтобы использовать эти методы в Visual Basic, объявите переменную нужного класса и используйте новую ключевое слово для назначения объекта переменной объекта. Ключевое слово Shared можно использовать, если необходимо убедиться, что создан только один экземпляр класса .

' 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

Необработанных ошибок в обработчиках событий

Одна из распространенных проблем взаимодействия связана с ошибками в обработчиках событий, которые обрабатывают события, вызванные COM-объектами. Такие ошибки игнорируются, если вы не проверка для ошибок с помощью On Error инструкций или Try...Catch...Finally . Например, следующий пример получен из проекта Visual Basic .NET, который содержит ссылку на COM-объект библиотеки Microsoft ActiveX Data Objects 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 =
    "Provider=Microsoft.Jet.OLEDB.4.0;" &
    "Data Source=C:\NWIND.MDB"
    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

В этом примере возникает ошибка, как ожидалось. Однако если вы попытаетесь использовать тот же пример без Try...Catch...Finally блока , ошибка игнорируется, как если бы вы использовали инструкцию OnError Resume Next . Без обработки ошибок деление на ноль автоматически завершается ошибкой. Поскольку такие ошибки никогда не вызывают необработанных ошибок исключений, важно использовать определенную форму обработки исключений в обработчиках событий, обрабатывающих события из COM-объектов.

Основные сведения об ошибках COM-взаимодействия

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

Try
    ' Place call to COM object here.
Catch ex As Exception
    ' Display information about the failed call.
End Try

Вы можете найти такие сведения, как описание ошибки, HRESULT и источник com-ошибок, изучив содержимое объекта исключения.

Проблемы с элементом ActiveX

Большинство элементов ActiveX, работающих с Visual Basic 6.0, работают с Visual Basic .NET без проблем. Исключениями main являются элементы управления-контейнеры или элементы управления, которые визуально содержат другие элементы управления. Ниже приведены некоторые примеры старых элементов управления, которые неправильно работают с Visual Studio.

  • Элемент управления кадром Microsoft Forms 2.0

  • элемент управления Up-Down, также известный как элемент управления спином

  • Элемент управления "Вкладка Шеридан"

Существует только несколько обходных путей для неподдерживаемых проблем с элементом ActiveX. Вы можете перенести существующие элементы управления в Visual Studio, если у вас есть исходный код. В противном случае можно проверка с поставщиками программного обеспечения для обновленного . Совместимые с NET версии элементов управления для замены неподдерживаемых элементов ActiveX.

Передача свойств ReadOnly элементов управления ByRef

Visual Basic .NET иногда вызывает com-ошибки, такие как "Ошибка 0x800A017F CTL_E_SETNOTSUPPORTED", при передаче ReadOnly свойств некоторых старых элементов ActiveX в качестве ByRef параметров в другие процедуры. Аналогичные вызовы процедур из Visual Basic 6.0 не вызывают ошибку, а параметры обрабатываются так, как если бы они были переданы по значению. Сообщение об ошибке Visual Basic .NET указывает на то, что вы пытаетесь изменить свойство без процедуры свойства Set .

Если у вас есть доступ к вызываемой процедуре, можно предотвратить эту ошибку, используя ByVal ключевое слово для объявления параметров, которые принимают ReadOnly свойства. Пример:

Sub ProcessParams(ByVal c As Object)
    'Use the arguments here.
End Sub

Если у вас нет доступа к исходному коду вызываемой процедуры, можно принудительно передать свойство по значению, добавив дополнительный набор скобок вокруг вызывающей процедуры. Например, в проекте со ссылкой на COM-объект библиотеки Microsoft ActiveX Data Objects 2.8 можно использовать:

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

Развертывание сборок, которые предоставляют взаимодействие

Развертывание сборок, которые предоставляют COM-интерфейсы, представляет собой некоторые уникальные проблемы. Например, потенциальная проблема возникает, когда отдельные приложения ссылаются на одну сборку COM. Эта ситуация распространена, когда установлена новая версия сборки, а другое приложение по-прежнему использует старую версию сборки. При удалении сборки, которая использует библиотеку DLL, вы можете непреднамеренно сделать ее недоступной для других сборок.

Чтобы избежать этой проблемы, следует установить общие сборки в глобальный кэш сборок (GAC) и использовать MergeModule для компонента. Если вы не можете установить приложение в GAC, оно должно быть установлено в CommonFilesFolder в подкаталоге для конкретной версии.

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

См. также раздел