Desenvolvimento - C#

Você tem componentes COM e quer aproveitá-los em .NET?

É normal encontrarmos aplicações escritas que possuem componentes escritos em VB 6.0, por exemplo, numa aplicação em camadas: apresentação, negócio e dados. Os componentes do VB 6.0 são elementos chave para manter-se uma arquitetura em camadas e, conseqüentemente, tirar proveito da reutilização de código. Uma das principais preocupações de uma empresa antes de migrar para plataforma .NET é: Eu vou perder toda parte de negócio que foi escrita em VB 6.0? Pode ficar tranqüilo que não...

por Renato Guimarães



É normal encontrarmos aplicações escritas que possuem componentes escritos em VB 6.0, por exemplo, numa aplicação em camadas: apresentação, negócio e dados. Os componentes do VB 6.0 são elementos chave para manter-se uma arquitetura em camadas e, conseqüentemente, tirar proveito da reutilização de código. Uma das principais preocupações de uma empresa antes de migrar para plataforma .NET é: Eu vou perder toda parte de negócio que foi escrita em VB 6.0? Pode ficar tranqüilo que não porque o Visual Studio .NET já vem com uma ferramenta chamada Upgrade Wizard que vai te dar todo esse suporte na migração e, dependendo dos componentes utilizados, a migração pode ser feita quase de forma automática.

Além dessa, ainda ficam outras perguntas: Eu quero migrar só a camada de apresentação e continuar utilizando meus componentes ActiveX escritos em VB 6.0? Eu vou perder todo investimento nos componentes? Posso migrar a parte de negócio e ainda continuar com a camada de apresentação em VB 6.0?

Você não perderá os investimentos no VB 6.0 porque poderá reaproveitar todo código sem ter necessidade de migrar sua aplicação por completo. Você poderá migrar sua aplicação de forma Top-Down, ou seja, converte toda camada de apresentação para tirar o proveito das melhorias trazidas pelo .NET e, em seguida, aos poucos, vai migrando os componentes do VB 6.0. Outra forma seria o Bottom-Up onde você migra a camada de negócio e continua com a camada de apresentação usando VB 6.0. A forma Bottom-Up é bem mais complexa e trabalhosa. Mas, mesmo podendo acessar os componentes VB 6.0, é importante que você converta toda aplicação para .NET para tirar todo proveito do framework .NET.

Hoje vamos entender como acessar os componentes escritos em VB 6.0 em aplicações .NET; e como acessar componentes .NET em aplicações escritas em VB 6.0. Ao final, com o que será ensinado, você terá toda certeza que poderá migrar sua aplicação para VB.NET. Essa interoperabilidade de duas vias é a chave da migração de COM para .NET. Há um número de situações onde a interoperabilidade é útil:

  • Você não aprenderá tudo sobre .NET no mesmo dia. Leva um certo tempo para você aprender .NET.
  • Embora a conversão do VB 6.0 para VB.NET possa ser feita de forma automática com o Upgrade Wizard, nem tudo é convertido automaticamente. Você pode ter componentes que não podem ser convertidos para VB.NET devido a algumas mudanças na linguagem.
  • Você não pode, da noite para o dia, escrever todos componentes da sua aplicação em .NET. Sendo assim, é melhor migrar componente individualmente e testá-lo um a um enquanto ainda estiver interoperando com o código antigo.
  • Você pode está usando componentes COM de terceiros que você não tem o código fonte.
Chamando componentes COM com aplicações .NET

- Código não-gerenciado e Runtime-Callable Wrappers

Todo código que é gerado na plataforma .NET é chamado de código gerenciado. Gerenciado porque ele é controlado pelo CLR (Common Language Runtime) que fornece os seguintes serviços: integração entre linguagens, segurança, suporte a versões e coleta de objetos que não estão em uso (Garbage Collection). O código que não opera com o CLR é chamado de código não-gerenciado. Sendo assim, todo o código COM, por definição, é código não-gerenciado. Isto porque o COM foi lançado antes de existir o .NET e não dá suporte ao framework .NET (CLR), ou seja, não pode utilizar os serviços do CLR. Dessa forma não podemos misturar código gerenciado e não-gerenciado numa mesma aplicação porque o código não-gerenciado não reconhece o ambiente do CLR. O código gerenciado não depende só do CLR, mas espera que os outros componentes com os quais ele irá interagir também dependam.

A solução para esse problema é usar um Proxy. O Proxy é um parte de uma aplicação que aceita comandos de outros componentes, modifica-os e reenvia-os para outro componente. Na necessidade de chamar um código não-gerenciado de um código gerenciado temos um Proxy em particular que é chamado de Runtime-Callable Wrapper(RCW). A figura 1 mostra o esquema de como o RCW ultrapassa a fronteira existente entre o código gerenciado e o não-gerenciado. Temos um aplicação .NET acessando dois componentes COM: cliente.dll e servidor.dll.


Figura 1. Chamando código não-gerenciado através de Proxy

- Usando a ferramenta TlbImp.exe para converter os metadados do componente COM

As bibliotecas de tipo (type libraries) COM contém metadados para descrever a interface pública para o componente COM. Se você constrói uma dll ActiveX ou um executável ActiveX com Visual Basic, a biblioteca de tipos é enviada dentro da dll ou exe.

O SDK (Software Development Kit) possui uma ferramenta utilizada para fazer essa conversão - TlbImp.exe. TlbImp ler o metadado de uma biblioteca de tipo COM e cria um assembly compatível em .NET para chamar o componente COM. Essa ferramenta de linha de comando possui várias opções, tais como assinalar um assembly resultante com uma chave de criptografia ou resolve referências externas na biblioteca de tipos. A opção mais importante é /out, a qual permite você especificar o nome do assembly .NET resultante. Por exemplo, para converter a o componente ActiveX negocio.dll para um assembly em .NET com o nome NETnegocio.dll, usamos a seguinte linha de comando:

Tlbimp negocio.dll /out:NETnegocio.dll - Utilizando o Visual Studio.NET para acessar componentes diretamente

Usando o Visual Studio.NET você pode repetir os passos abaixo para adicionar uma referência a um componente COM:

  1. Clique no menu Project, e depois escolha Add Reference.
  2. Na caixa Add Reference, selecione a aba COM.
  3. Selecione a dll que você deseja usar na lista e clique em Select, ou use o botão Browse para localizar um componente que não é listado. O componente selecionado será adicionado na lista no final da tela. Veja figura 2.


    Figura 2. Tela onde é selecionado o componente COM para criar referência.

  4. Clique Ok para o VS.NET criar o RCWs para os componentes selecionados no seu projeto .NET.

Quando estiver concluído, você encontrará um dll, dentro da pasta \bin, que foi criada pelo VS.NET, com o nome derivado do nome do componente COM selecionado da versão 1.0. Por exemplo, se você faz referência a servidor.dll, o VS.NET criará o RCW no arquivo Interop.Servidor_1_0.dll.

O único problema em adicionar uma referência dessa forma é que você não tem a opção de assinalar o assembly com uma chave. Com isso, você não poderá colocar sua dll no Global Assembly Cache, no qual torna impossível compartilhar o componente com outras aplicações .NET.

Para instalar o componente COM na máquina onde você está seu Visual Studio.NET execute a seguinte linha de comando:

regsvr32 nomecomponente.dll

Será mostrada uma tela como a mostrada na figura 3:


Figura 3. Mensagem confirmando o registro do componente.

Chamando classes .NET em aplicações COM

- Código não-gerenciado e Runtime-Callable Wrappers

As aplicações COM podem chamar código que é exposto em classes .NET, mas esse código .NET não é acessado diretamente pela aplicação COM. Para isso, você precisa criar um Proxy conhecido como COM Callable Wrapper(CCW). Agora vamos conhecer a arquitetura do CCW, bem como os passos necessários para criar e distribuir classes .NET para serem usadas por aplicações COM.

Como já foi comentado, o código gerenciado não só depende do CLR, mas requer que os componentes com os quais ele interagem devem depender do CLR também. Devido ao COM não se comunicar com o CLR, eles não podem chamar código gerenciado diretamente.

A solução para esse problema é usar um Proxy. Como já vimos, um Proxy é um parte de uma aplicação que aceita comandos de outros componentes, modifica-os e reenvia-os para outro componente. Um tipo particular de Proxy usado na chamada de código gerenciado a partir de aplicação com código não-gerenciado é conhecido como CCW, ou COM Callabe Wrapper. A figura 4 como o CCW resolve essa fronteira entre os dois ambientes. A figura mostra uma aplicação COM, dois componentes .NET, e a tecnologia necessária para comunicá-los.


Figura 4 Chamando código gerenciado através do Proxy.

Existem dois pontos importantes que você deve levar em consideração quando estiver criando classes .NET que serão usadas por aplicações COM.

1. Primeiro, defina explicitamente uma interface no seu código .NET, por exemplo, o trecho de código da listagem 1 define uma interface chamada IOpeMatematica e uma classe que implementa a interface. Implementando as funcionalidades através de interfaces tem um grande benefício para os clientes COM. .NET mantém interfaces consistentes com versões anteriores quando estiver gerando CCWs. Isso evita que as mudanças feitas nas classes .NET afetem os clientes COM.

Listagem 1 Cria e implementa uma interface

using System;

namespace ComponenteDotNet{

	public interface IOpeMatematica{
		int Dobro(int numero);
		int Quadrado(int numero);
	}

	public class OperacoesMatematicas : IOpeMatematica{
		public int Dobro(int numero){
			return numero * 2;
		}

		public int Quadrado(int numero){
			return numero * numero;
		}
	}
}

2. Qualquer classe .NET que for visível por clientes COM deve ser declarada como pública. As ferramentas para criar o CCW só define os tipos baseado nas classes públicas. A mesma regra aplica-se a métodos, propriedades e eventos que serão usados pelos clientes.

Você deve assinar o assembly com uma chave criptografada, ou seja, assiná-lo com um strong name. Assinando o assembly com um strong name garante que não será mudado após ter sido publicado. O strong name é um requisito para todos assemblies globais, nos quais são assemblies que são compartilhados por múltiplos clientes. É possível usar um assembly não assinado através de um cliente COM através da instalação do assembly direto no diretório do cliente COM, no qual é chamado de assembly privado.

É uma boa prática assinar todos os assemblies, mesmo os assemblies privados. Isto ajudará na geração de CLSIDs melhores para classes gerenciadas, e ajuda a evitar colisões entre as classes e diferentes assemblies.

Para criar um strong name você usa a ferramenta sn.exe ou pode usar a interface gráfica do Visual Studio.NET.

- Gerar o strong name através da linha de comando

Existem muitas opções para essa ferramenta de linha de comando. Caso tenha alguma dúvida, você pode digitar sn /? para ver a lista completa de opções. A opção usada para assinar um assembly é -k, no qual cria um arquivo com a chave. Por default, os arquivos com as chave terminam com a extensão .snk. Por exemplo, para criar uma chave chamada appDotNet.snk, você pode usar essa linha de comando: sn -k appDotNet.snk.

- Gerar o strong name usando o Visual Studio.NET

No solution Explorer, clique com o botão direito do mouse sobre o projeto, selecione a opção Properties. Clique na pasta Commom Properties e depois a opção Strong Name. Selecione a caixa com rótulo Generate Strong Name Using. Clique em Generate Key para gerar um arquivo de chave e adicione ao seu projeto. Clique Ok para fechar a janela de propriedades.

- Registrar o assembly e criar um Type Library

Após ter criado suas classes .NET, você pode utilizá-la tanto para acesso através de clientes COM quanto aplicações .NET. Mas, ainda existem algumas etapas para que seu assembly seja disponibilizado para aplicações COM. Abra a linha de comando do Visual Studio.NET (Clique Start | Programs | Microsoft Visual Studio .NET | Visual Studio .NET Tools | Visual Studio .NET Command Prompt), mude o diretório para pasta onde se encontra o assembly que você quer disponibilizar, por exemplo, appDotNet.dll, e digite: Regasm /tlb:appDotNet.tlb appDotNet.dll.

A ferramenta regasm.exe criará um type library e irá registrá-lo no registro do Windows para que as classes de appDotNet.dll estejam disponíveis aos clientes COM.

Adicionar o Assemby ao Global Assembly Cache

Finalmente, para tornar seu assembly disponível a qualquer cliente COM que esteja em qualquer diretório do seu disco, retorne a linha de comando do Visual Studio .NET e digite o seguinte comando: Gacutil /i appDotNet.dll.

Conclusões

Mesmo que a chamada a componentes COM dentro do código gerenciado seja simples, você não deve considerar isso permanentemente. Depois de um certo tempo, você vai querer migrar componentes pesados para código .NET nativo. Isso será de grande importância porque adicionará as novas características da linguagem .NET ao seu código e, conseqüentemente, o deixará mais rápido através da eliminação do RCW.

Chamar componentes .NET dentro de um componente COM não é uma tarefa tão fácil. Você precisa fazer mudanças explicitamente no seu código para seu componente .NET se encaixar nesse cenário. Mas, mesmo assim, as modificações são mínimas com relação aos benefícios obtidos com acesso aos componentes .NET.

Renato Guimarães

Renato Guimarães - Bacharel em Sistemas de Informação e trabalha com tecnologia da informação há mais de 15 anos.