Desenvolvimento - C#

Criando DLLs no Microsoft.NET

Assim como no Windows, a arquitetura Microsoft .NET permite a criação de DLLs que podem ser compartilhadas por vários programas. O .NET, contudo, traz várias novidades adicionais na criação de DLLs...

por Mauro Sant'Anna



Assim como no Windows, a arquitetura Microsoft .NET permite a criação de DLLs que podem ser compartilhadas por vários programas. O .NET, contudo, traz várias novidades adicionais na criação de DLLs:

  • Enquanto as DLLs Windows contém funções, as DLLs .NET contém tipos.
  • Dentre os vários tipos possíveis, a class (classe) é o tipo mais interessante que pode existir dentro das DLLs.
  • As DLLs contêm não apenas o código, mas também informações de tipo completas do que está dentro dela. Dentre as várias informações, estão os nomes dos tipos, métodos, campos e propriedades.

Esta informação adicional é usada em várias situações, mas a mais importante é garantir a integridade do sistema de tipos em tempo de execução. Não é possível executar uma conversão de tipo inválida, pois todas as conversões são validadas em tempo de execução. Boa parte da segurança e integridade da nova plataforma depende disso. Esta informação de tipo é exposta aos programadores nonamespace “System.Reflections”.

Para quem está acostumado com o Delphi, este é basicamente o mesmo esquema usado nos “runtime packages”, com duas principais diferenças:

  • O código executável das DLLs, correspondente no Delphi ao arquivo “BPL”, contém obrigatoriamente informações de tipo, que no Delphi ficam separadas no arquivo “DCP”;
  • O Delphi provê informação de tipo em tempo de execução apenas para os campos, métodos e propriedades declarados na seção “published” e, ainda assim, apenas para as classes “registradas”. No .NET, tudo tem informação de tipo em tempo de execução, sem exceções.

A criação de uma DLL contendo classes é bastante simples. No Visual Studio.NET Beta 2, peça a criação de um projeto do tipo “Class Library”. Na verdade, não somos obrigados a colocar classe nenhuma no projeto. O que vale mesmo é que estamos criando uma “Library” (DLL):

Criando uma DLL

Figura 1: Criando uma DLL

Vamos colocar uma classe simples dentro do projeto:

Listagem 1:

using System; 
namespace MinhaDLL { 
public class Simples { 
decimal N; 
public Simples(decimal X) { 
AjustaValor(X); 
} 
public Simples() { 
AjustaValor(0); 
} 
public void AjustaValor(decimal X) { 
N = X; 
} 
public decimal PegaValor() { 
return N; 
} 
} 
}

Depois de compilar a DLL, é possível examinar seu conteúdo com o “IL Disassembler” (ildasm.exe), localizado no diretório \Program Files\Microsoft.NET\FrameworkSDK\Bin:

Examinando o conteúdo da DLL

Figura 2: Examinando o conteúdo da DLL

Para testar a DLL, criaremos um projeto em modo console:

Criando projeto Console

Figura 3: Criando projeto Console

Para chamar a classe dentro da DLL, temos duas opções:

  • Via “early biding”, resolvendo as chamadas em tempo de compilação.
  • Via “late biding”, resolvendo as chamadas em tempo de execução.

Early Biding

Neste caso criaremos uma “referência” à DLL dentro do projeto de teste. Clique com o botão direito sobre “References” e peça “Add Reference”:

Adicionando referência

Figura 4: Adicionando referência

Selecione a DLL criada recentemente clicando em “Browse”:

Selecionando a DLL para referenciar

Figura 5: Selecionando a DLL para referenciar

Veja o código de teste:

Listagem 2:

using System; 
namespace ChamaDLL { 
class Class1 { 
static void Main(string[] args) { 
MinhaDLL.Simples MD = new MinhaDLL.Simples(10); 
decimal X = MD.PegaValor(); 
Console.WriteLine(X); 
} 
} 
}

No exemplo acima, o executável de testes depende da DLL para ser carregado. Caso a DLL não esteja disponível, o programa nem roda:

Erro por falta da DLL

Figura 6: Erro por falta da DLL

Podemos resolver a chamada de maneira totalmente dinâmica usando “Late Biding”.

Late Biding

Para chamar a classe via “Late Biding”, usaremos o suporte de “Reflections” do .NET Framework. Copie a DLL para o mesmo diretório do aplicativo e use o seguinte programa em modo console:

Listagem 3:

using System.Reflection; 
namespace ChamaDLL { 
class Class1 { 
static void Main(string[] args) { 
// Carrega DLL dado seu nome 
Assembly Lib = Assembly.Load("MinhaDLL"); 
// Cria um objeto dado seu tipo 
object MD = Lib.CreateInstance("MinhaDLL.Simples"); 
// Chama um método 
MD.GetType().InvokeMember("AjustaValor", 
BindingFlags.InvokeMethod, null, MD, 
new object[] {10.0m}); 
// Chama outro método 
decimal X = (decimal) MD.GetType().InvokeMember( 
"PegaValor", BindingFlags.InvokeMethod, null, 
MD, null); 
System.Console.WriteLine(X); 
} 
} 
}

Segurança e DLL Hell

A DLL feita neste programa foi copiada no diretório do próprio executável que a usa, sendo também chamada de “private assembly”, pois é acessada apenas dentro de um pacote de software. Este é um caso bastante comum, que não necessita de nenhuma preocupação adicional de segurança ou controle de versão. No entanto, se a DLL for ser compartilhada, existem algumas preocupações adicionais.

No Windows, temos sérios problemas de controle de versões de DLL:

  • Um programa de terceiros pode instalar uma versão diferente de uma DLL compartilhada, fazendo o seu programa parar de funcionar.
  • Um programa malicioso pode instalar uma DLL diferente, que viole a segurança do sistema.

O .NET tem um protocolo bastante rigoroso para instalação de DLLs compartilhadas, também chamadas de “shared assemblies”, usando criptografia de chave pública. Este protocolo exige os seguintes passos:

  • Precisamos “assinar” a DLL usando uma chave criptográfica única da nossa empresa.
  • A DLL é instalada com um utilitário específico, chamado “gacutil.exe”.

Conclusão

A arquitetura Microsoft.NET tem um mecanismo bastante poderoso e flexível para a divisão do código em várias DLL, sem perder a “tipagem” forte e aumentando a integridade e segurança.

Mauro Sant'Anna

Mauro Sant'Anna - Mauro tem mais de 20 anos de experiência no desenvolvimento de software, com produtos publicados no Brasil, Portugal e Estados Unidos, além de extensa experiência em treinamento e consultoria no desenvolvimento de software, tanto criando material como ministrando cursos.
Mauro é um "Microsoft Most Valuable Professional" (MVP - www.microsoft.com/mvp), “Microsoft Regional Director” (RD - www.microsoft.com/rd), membro do INETA Speaker’s Bureau (www.ineta.org) e possui as certificações MCP, MCSA (Windows 2000/2003), MCAD (C# e VB), MCDBA, MCSE (Windows 2000/2003).
Sua empresa, a M. A. S Informática (www.mas.com.br), treinou centenas de turmas em desenvolvimento de software nos últimos anos.