Personas que lo han encontrado útil: 0 de 1 - Valorar este tema

Solución de problemas de interoperabilidad

En la interoperabilidad de COM y el código administrado de .NET Framework, es posible que se le presenten algunos de los siguientes problemas comunes.

En ocasiones es posible que necesite utilizar tipos de datos que no forman parte de .NET Framework. Los ensamblados de interoperabilidad controlan la mayor parte del trabajo para objetos COM, pero es posible que tenga que controlar los tipos de datos utilizados cuando exponga a COM objetos administrados. Por ejemplo, las estructuras de las bibliotecas de clases deben especificar el tipo no administrado BStr en las cadenas enviadas a los objetos COM creados con Visual Basic 6.0 y versiones anteriores. En estos casos, puede utilizar el atributo MarshalAsAttribute para exponer los tipos administrados como tipos no administrados.

En Visual Basic 6.0 y versiones anteriores, las cadenas se exportan a objetos COM como secuencias de bytes sin un carácter de terminación de tipo NULL. Por compatibilidad con otros lenguajes, Visual Basic 2005 incluye un carácter de terminación al exportar cadenas. La mejor forma de solucionar esta incompatibilidad es exportar cadenas sin carácter de terminación como matrices de tipo Byte o Char.

Las jerarquías de clases administradas desaparecen cuando las clases se exponen como objetos COM. Por ejemplo, si define una clase base con un miembro y después hereda la clase base en una clase derivada expuesta como un objeto COM, los clientes que utilizan la clase derivada en el objeto COM no podrán utilizar los miembros heredados. Los miembros de la clase base sólo son accesibles desde objetos COM como instancias de una clase base, y sólo en el caso de que la clase base también se cree como un objeto COM.

Aunque se pueden crear métodos sobrecargados con Visual Basic, COM no los admite. Cuando una clase que contiene métodos sobrecargados se expone como objeto COM, se generan nombres de método nuevos para los métodos sobrecargados.

Suponga, por ejemplo, que una clase tiene dos sobrecargas del método Synch. Si la clase se expone como objeto COM, los nombres de método nuevos generados podrían ser Synch y Synch_2.

El cambio de nombre puede producir dos problemas para los consumidores del objeto COM.

  1. Es posible que los clientes no esperen los nombres de método generados.

  2. Los nombres de método generados en la clase expuesta como objeto COM pueden cambiar al agregar nuevas sobrecargas a la clase o a su clase base, lo que puede provocar problemas de versión.

Para resolver ambos problemas, asigne un nombre único a cada método, en lugar de utilizar la sobrecarga, cuando desarrolle objetos que se van a exponer como objetos COM.

Los ensamblados de interoperabilidad se utilizan casi como si fueran equivalentes de código administrado a los objetos COM que representan. Sin embargo, como son encapsuladores y no objetos COM reales, hay algunas diferencias entre el uso de ensamblados de interoperabilidad y ensamblados estándar. Son diferencias en la exposición de clases y los tipos de datos para parámetros y valores devueltos.

A diferencia de las clases de los ensamblados estándar, las clases COM se exponen en ensamblados de interoperabilidad como una interfaz y una clase que representa la clase COM. El nombre de la interfaz es idéntico al de la clase COM. El nombre de la clase de interoperabilidad es igual al de la clase COM original, pero con la palabra "Class" anexada. Por ejemplo, suponga que tiene un proyecto con una referencia a un ensamblado de interoperabilidad para un objeto COM. Si la clase COM se denomina MyComClass, IntelliSense y el Examinador de objetos muestran una interfaz denominada MyComClass y una clase denominada MyComClassClass.

Por lo general, una instancia de una clase de .NET Framework se crea mediante la instrucción New con un nombre de clase. La representación de una clase COM mediante un ensamblado de interoperabilidad es el caso en el que se puede utilizar la instrucción New con una interfaz. A menos que utilice la clase COM con una instrucción Inherits, puede utilizar la interfaz del mismo modo que utilizaría una clase. En el código siguiente se muestra cómo se crea un objeto Command en un proyecto que tiene una referencia al objeto COM de Microsoft ActiveX Data Objects 2.8 Library:

Dim cmd As New ADODB.Command

Sin embargo, si utiliza la clase COM como base para una clase derivada deberá utilizar la clase de interoperabilidad que representa la clase COM, como en las líneas siguientes:

Class DerivedCommand
    Inherits ADODB.CommandClass
End Class

NoteNota

Los ensamblados de interoperabilidad implementan implícitamente interfaces que representan clases COM. No debe intentar utilizar la instrucción Implements para implementar estas interfaces; si lo hace, se producirá un error.

A diferencia de los miembros de los ensamblados estándar, los miembros de los ensamblados de interoperabilidad pueden tener tipos de datos distintos de los utilizados en la declaración original del objeto. Aunque los ensamblados de interoperabilidad convierten implícitamente los tipos COM en tipos compatibles con Common Language Runtime, debe tener en cuenta los tipos que utiliza en los dos lados para evitar errores en tiempo de ejecución. Por ejemplo, en los objetos COM creados con Visual Basic 6.0 y versiones anteriores, los valores de tipo Integer adquieren el tipo de .NET Framework equivalente, Short. Se recomienda utilizar el Examinador de objetos para examinar las características de los miembros importados antes de utilizarlos.

La mayoría de los objetos COM se utilizan creando una instancia de una clase COM mediante la palabra clave New y, a continuación, llamando a métodos del objeto. Existe una excepción a esta regla relacionada con los objetos COM que contienen clases COM AppObj o GlobalMultiUse. Estas clases son similares a los métodos de nivel de módulo de las clases de Visual Basic 2005. Visual Basic 6.0 y versiones anteriores crea implícitamente instancias de estos objetos la primera vez que se llama a uno de sus métodos. Por ejemplo, en Visual Basic 6.0 es posible agregar una referencia a Microsoft DAO 3.6 Object Library y llamar al método DBEngine sin crear primero una instancia:

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

Visual Basic 2005 requiere que siempre se creen instancias de los objetos COM antes de utilizar sus métodos. Para utilizar estos métodos en Visual Basic 2005, declare una variable de la clase que desee y utilice la nueva palabra clave para asignar el objeto a la variable de objeto. Puede utilizar la palabra clave Shared para asegurarse de que sólo se crea una instancia de la clase.

' 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

Un problema habitual de interoperabilidad implica a los errores de controladores de eventos que controlan eventos producidos por objetos COM. Estos errores se omiten a menos que se compruebe específicamente la existencia de errores mediante instrucciones On Error o Try...Catch...Finally. Por ejemplo, el ejemplo siguiente procede de un proyecto de Visual Basic 2005 que tiene una referencia al objeto COM de Microsoft ActiveX Data Objects 2.8 Library.

' 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

Este ejemplo produce un error, según lo esperado. Sin embargo, si intenta ejecutar el mismo ejemplo sin el bloque Try...Catch...Finally, el error se omitirá como si hubiera utilizado la instrucción OnError Resume Next. Sin control de errores, la división por cero produce un error pero no lo comunica. Dado que tales errores nunca producen errores de excepción no controlados, es vital utilizar algún tipo de control de excepciones en los controladores de eventos que controlan eventos de objetos COM.

Errores de interoperabilidad COM

Sin control de errores, las llamadas de interoperabilidad suelen generar errores que proporcionan poca información. Siempre que sea posible, utilice control de errores estructurado para proporcionar más información sobre los errores en el momento en que se produzcan. Esto puede resultar especialmente útil durante la depuración de aplicaciones. Por ejemplo:

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

Puede examinar el contenido del objeto de excepción para averiguar información tal como la descripción del error, HRESULT y el origen de los errores COM.

La mayor parte de los controles ActiveX que funcionan con Visual Basic 6.0 funcionan con Visual Basic 2005 sin problemas. Las principales excepciones son los controles contenedores, o controles que contienen visualmente a otros controles. Estos son algunos ejemplos de controles más antiguos que no funcionan correctamente con Visual Studio:

  • Control Microsoft Forms 2.0 Frame

  • Control Arriba-Abajo, también conocido como control giratorio

  • Control Tab Sheridan

Sólo hay unas pocas soluciones para los problemas de controles ActiveX incompatibles. Es posible migrar controles existentes a Visual Studio si se dispone del código fuente original. Si no es así, puede consultar a los proveedores de software para ver si disponen de versiones actualizadas de los controles compatibles con .NET para sustituir los controles ActiveX incompatibles.

Visual Basic 2005 produce a veces errores COM como "Error 0x800A017F CTL_E_SETNOTSUPPORTED" cuando se transfieren propiedades ReadOnly de algunos controles ActiveX antiguos como parámetros ByRef a otros procedimientos. Las llamadas de procedimiento similares desde Visual Basic 6.0 no producen ningún error; los parámetros se tratan como si se hubieran pasado por valor. El mensaje de error que se ve en Visual Basic 2005 es el objeto COM que informa de que se está intentando cambiar una propiedad que no tiene un procedimiento Set de propiedad.

Si tiene acceso al procedimiento al que se está llamando, puede utiliza la palabra clave ByVal para declarar parámetros que acepten propiedades ReadOnly y, así, evitar el error. Por ejemplo:

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

Si no tiene acceso al código fuente de la propiedad a la que se está llamando puede forzar que se pase la propiedad por valor; para ello, agregue un conjunto adicional de llaves alrededor del procedimiento que hace la llamada. Por ejemplo, en un proyecto que tenga una referencia al objeto COM de Microsoft ActiveX Data Objects 2.8 Library, se puede utilizar:

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

Implementar ensamblados que expongan interfaces COM supone algunas dificultades. Por ejemplo, un posible problema se produciría si aplicaciones independientes hacen referencia al mismo ensamblado COM. Es una situación normal cuando se instala una nueva versión de un ensamblado habiendo otra aplicación que utiliza aún la versión antigua de ese ensamblado. Al desinstalar cualquier ensamblado que comparta un archivo DLL, impedirá que se disponga de otros ensamblados sin desearlo.

Para evitarlo, debe instalar ensamblados compartidos en la caché de ensamblados global (GAC) y que el componente utilice un MergeModule. Si no puede instalar la aplicación en la GAC, deberá instalarla en CommonFilesFolder en un subdirectorio específico para esa versión.

Los ensamblados no compartidos deberán instalarse en el mismo nivel en el directorio de la aplicación que hace la llamada.

¿Le ha resultado útil?
(Caracteres restantes: 1500)
Contenido de la comunidad Agregar