Utilizar biblioteca de clases .NET en Access. Tercera aproximación a la Interoperabilidad COM

Autodual

En los anteriores artículos sobre utilizar bibliotecas de clases .NET en Access, hemos llegado a dos aproximaciones que nos van introduciendo en la Interoperabilidad COM.

En el primer artículo nos lanzábamos directamente a crear la clase en C# desde Visual Studio, crear el ensamblado visible desde COM y registrar la interoperabilidad. Resultaba sencillo y además era fácilmente entendible sin meternos en profundidad.

Con este primer método, veíamos varios inconvenientes aunque funcionara “correctamente”:

  • Late-Binding: Puede ser peligroso ya que no sabemos si existen los métodos hasta ejecutar.
  • Relacionado con lo anterior, no funciona el Intellisense de VBA.
  • Compatibilidad binaria: Se rompe si modificamos la clase.
  • Cambio de equipo: Mientras estemos en el equipo de desarrollo no hay problema, pero si cambiamos…


En el siguiente artículo sobre utilizar bibliotecas de clases .NET en Access utilizando una plantilla de Clase COM llegamos a una aproximación bastante más elegante. Solucionaba parte de los problemas de la primera aproximación (tenemos Intellisense, early-binding, no rompemos la compatibilidad binaria al crear nuevos métodos, podemos crear eventos, etc) y además era incluso más sencilla de crear. Pero teníamos los siguientes problemas:

  • Los métodos no heredaban de la clase Object
  • Problemas a la hora de distribuir la aplicación (fuera del equipo de desarrollo)
  • Teníamos que utilizar Visual Basic .NET (esto no es un problema, pero como estoy intentando aprender C#, prefiero utilizarlo)

En este artículo explicaré otra manera de utilizar bibliotecas .NET en Access que aunque Microsoft no recomienda su utilización, mucha gente la sigue utilizando. Vamos a empezar, para los que no habéis leído el resto de artículos, empiezo desde cero. Creamos un proyecto nuevo en Visual Studio:

Nuevo Proyecto

Nuevo Proyecto

Como este método si que se puede crear eb C#, seleccionamos Plantilla de Visual C# en el menú izquierdo y y luego Biblioteca de Clases en la parte derecha:

Biblioteca de clases

Biblioteca de clases

Se nos crea la clase y veremos esto:

Clase

Clase

Para no cambiar, voy a utilizar el código de los 2 anteriores artículos. Además, si habéis leído el artículo sobre mis intenciones de renovación, observaréis que la función (aunque realmente no hace nada…) es muy significativa.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ProgramadorDePalo
{
    public class Vida
    {
        public Boolean EstarVivo(Boolean renovarse)
        {
            Boolean vivo = false;
            if (renovarse == true)
            {
                vivo = true;
            }
            return vivo;
        }

    }
}

Vamos ahora con la parte que Microsoft no recomienda. tendremos que añadir el espacio de nombres system.Runtime.InteropServices para que nos permita utilizar ClassInterfaceType. ClassInterfaceType indica el tipo de interfaz de clase que debe generarse para una clase expuesta a COM, en caso de que se genere una interfaz. En nuestro caso utilizaremos ClassInterfaceType.AutoDual, que hará que la clase exponga todos sus miembros a COM y además exponga también los heredades de la clase Object. Veamos cómo queda el código:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;

namespace ProgramadorDePalo
{
    [ClassInterface(ClassInterfaceType.AutoDual)]
    public class Vida
    {
        public Boolean EstarVivo(Boolean renovarse)
        {
            Boolean vivo = false;
            if (renovarse == true)
            {
                vivo = true;
            }
            return vivo;
        }

    }
}

Ahora vamos a revisar información de ensamblado ya que dependiendo de si habéis seguido el resto de artículos o no, lo tendréis de una manera. Nos dirigimos al menú Proyecto->Propiedades del proyecto. En el apartado “Aplicación” pinchamos “Información de ensamblado”:

Información de ensamblado

Información de ensamblado

Nos aseguramos de activar la casilla “Crear ensamblado visible a través de COM”:

Visible a través de COM

Visible a través de COM

También podemos añadirlo manualmente en AssemblyInfo.cs:

using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// La información general sobre un ensamblado se controla mediante el siguiente
// conjunto de atributos. Cambie estos atributos para modificar la información
// asociada con un ensamblado.
[assembly: AssemblyTitle("ProgramadorDePalo")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("ProgramadorDePalo")]
[assembly: AssemblyProduct("ProgramadorDePalo")]
[assembly: AssemblyCopyright("Copyright © ProgramadorDePalo 2014")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

// Si establece ComVisible como false, los tipos de este ensamblado no estarán visibles
// para los componentes COM.  Si necesita obtener acceso a un tipo de este ensamblado desde
// COM, establezca el atributo ComVisible como true en este tipo.
[assembly: ComVisible(true)]

// El siguiente GUID sirve como identificador de typelib si este proyecto se expone a COM
[assembly: Guid("0c17d2f8-db38-4a52-9429-8aeb52e21980")]

// La información de versión de un ensamblado consta de los cuatro valores siguientes:
//
//      Versión principal
//      Versión secundaria
//      Número de compilación
//      Revisión
//
// Puede especificar todos los valores o establecer como predeterminados los números de compilación y de revisión
// mediante el carácter '*', como se muestra a continuación:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

La linea importante es:

[assembly: ComVisible(true)]

Por cierto, si queremos que en vez de la clase, todo el ensamblado sea visible a COM, añadiremos en AssemblyInfo.cs la siguiente linea:

[Assembly: ClassInterface(ClassInterfaceType.AutoDual]

Ahora tenemos que ir a de vuelta al menú Proyecto->Propiedades del proyecto, nos dirigimos a la sección “Compilar” y nos aseguramso de que la casilla de verificación “Registrar para interoperabilidad COM” esté desactivada, esta vez lo vamos a hacer manual:

No registrar COM

No registrar COM

AHora vamos a compilar la librería para depués registrarla. Vamos al menú compilar->Generar solución.

Generar Solución

Generar Solución

Se nos habrá creado la biblioteca dll en la carpeta de nuestro proyecto\bin\Debug. Ahora tenemos que registrarla en el equipo y para ello necesitamos ir a la carpeta donde tengamos regasm.exe (en mi caso C:\Windows\Microsoft.NET\Framework\v4.0.30319) o utilizar el símbolo de sistema de Visual Studio (Inicio, Todos los programas, Microsoft Visual Studio, Visual Studio Tools y, a continuación, clic en Símbolo del sistema) de Visual Studio. Ejecutamos lo siguiente:

regasm c:\ruta\ProgramadorDePalo.dll /tlb -> Donde “ruta” será la ruta hasta nuestra biblioteca

Ahora ya si que tendremos la librería de tipos (ProgramadorDePalo.tlb) creada. En principio parece más complicado que dejar que Visual Studio lo haga manual, pero tenemos una gran ventaja, podemos transportar nuestra aplicación a otros equipos (o así debería de ser por lo menos). La copiamos a la carpeta donde tengamos nuestro proyecto de Access y la añadimos desde el menú Herramientas->Referencias:

Referencias

Referencias

Abrimos un módulo y creamos una función para probar nuestra nueva biblioteca de clases. Primero pulsamos F2 para abrir el examinador de objetos y ver si todo es correcto:

Examinador de objeto

Examinador de objeto

Podemos observar que la clase es accesible, que aparecen los métodos y que además, tenemos disponibles los métodos heredados de la clase object. Vamos a probar a ver si funciona. Creamos una función de prueba:

Function probar(ByVal estadoRen As Boolean) As Boolean

End Function

Creamos un nuevo objeto ProgramadorDePalo y de la clase vida:

Biblioteca ya creada

Biblioteca ya creada

Sigue funcionando correctamente, igual que en los anteriores artículos. Veamos qué pasa con la clase:

Clase

Clase

Y por último intentamos llamar al método:

Llamar método

Llamar método

Como véis todo es correcto y la función devuelve el valor correctamente. Es decir, este método nos añade varias cosas al método anterior. Tenemos todos los métodos heredados de la clase object y es fácilmente portable. Además seguimos teniendo Intellisense y early-binding.

Pero hay un gran problema con este método, perdemos la compatibilidad binaria con el cliente. Si recordáis el anterior artículo, podíamos crear un método nuevo desde Visual Studio o modificarlo y al compilar la biblioteca todo era visible desde Access. Con este método en cambio, no podremos hacerlo Hacemos una prueba, creamos una copia del método EstarVivo y lo llamamos Prueba2:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;

namespace ProgramadorDePalo
{
    [ClassInterface(ClassInterfaceType.AutoDual)]
    public class Vida
    {
        public Boolean EstarVivo(Boolean renovarse)
        {
            Boolean vivo = false;
            if (renovarse == true)
            {
                vivo = true;
            }
            return vivo;
        }

        public Boolean Prueba2(Boolean renovarse)
        {
            Boolean vivo = false;
            if (renovarse == true)
            {
                vivo = true;
            }
            return vivo;
        }
    }
}

Volvemos a generar la biblioteca de clases, siempre teniendo cuidado de no tener nuestra aplicación Access abierta. Lo que yo suelo hacer para no tener que mover las bibliotecas de sitio cada vez que generamos de nuevo el proyecto, es cambiar la ruta de acceso de los resultados. Para ello nos dirigimos a las propiedades del proyecto, apartado compilar y modificamos la ruta:

Ruta de acceso de los resultados

Ruta de acceso de los resultados

Ahora abrimos Access y vamos de nuevo al examinador de objetos pulsando F2:

Examinador de objeto

Examinador de objeto

Como véis, todo sigue igual, el nuevo método no es visible. Podéis pensar que puede ser por no haber vuelto a generar la librería de tipos, pero no tiene nada que ver. Simplemente ocurre que ha cambiado la interfaz. Para hacer visible ese método necesitaríamos crear una clase nueva que heredara de la primera. Por todo esto Microsoft no recomienda este método, así que en principio tengo que desaconsejarlo.

En el siguiente artículo terminaremos la serie de artículos y llegaremos a la solución óptima.

The following two tabs change content below.
Arkaitz Arteaga
Llevo más de 10 años programando, sobre todo en Visual Basic y con bases de datos Access. Para mí, VBA y Access siguen siendo herramientas muy potentes. He desarrollado varios proyectos con PHP y MySql. Si sumo las webs que he tenido, probablemente pasaría de 100. Ahora prefiero dedicar todo mi esfuerzo a este blog (aunque sigo manteniendo unas cuantas...). Trabajo en la administración pública (si, soy funcionario), pero he trabajado en pequeñas empresas e incluso en una "grande" de las telecomunicaciones. Ultimamente estoy bastante metido en abrirme nuevos horizontes con C# y .NET. Renovarse o morir!

2 Respuestas a Utilizar biblioteca de clases .NET en Access. Tercera aproximación a la Interoperabilidad COM

  1. Toda esta serie me está siendo de gran ayuda. Muchas gracias, maestro.

  2. Muchas gracias a ti. Este tipo de comentarios son lo que me hacen seguir adelante, meter horas de investigación, horas escribiendo, horas administrando el blog…

    Si no fuera por gente como tú, esto no merecería la pena.

    Mil gracias.

Deja un comentario