Translate this page now :



Gostou da Página?
Clique no botão abaixo para indicar esta página para um amigo!



Pesquisa personalizada
Pesquisar Dicas:








Quer saber mais?
Torne-se um MCP em Visual Basic
Faça um treinamento na Búfalo Informática


Resolvendo problemas de compatibilidade binária


Quando se desenvolve grandes sistemas em camadas, onde se tem componentes chamando componentes, um grande problema desses sistemas é manter a compatibilidade binária entre os componentes. Se um programador se distrair, a compatibilidade binária pode ser perdida e o sistema simplesmente parar.

Em muitos ambientes de desenvolvimento o sistema passa por vários estágios, tal como desenvolvimento, homologação e produção. Se a compatibilidade binária é quebrada dentro de um destes estágios, é facilmente identificável. Mas se for quebrada entre os estágios (por exemplo, um componente inserido em homologação não é compatível com o mesmo em desenvolvimento) fica muito difícil identificar o problema antes que tudo pare e cause graves consequencias.

Infelizmente não existe um recurso nativo do sistema operacional que possa nos dizer se dois componentes possuem ou não a compatibilidade binária. Porém isso não nos impede de criar esse recurso.

Mas o mecanismo da compatibilidade binária esconde alguns mistérios a mais. Os programadores sabem que para manter a compatibilidade binária é necessário que não hajam alterações na interface. Porém o Visual Basic é muito amigável com os programadores e permite que mesmo que hajam alterações em parâmetros ou inserção de novos métodos a compatibilidade binária seja mantida. Porém isso tem um custo.

Vamos imaginar um cenário. O componente A utiliza o componente B e o componente B sempre é compilado com a compatibilidade binária. Mas compilar o componente B, que já ganhou muitos novos métodos, com compatibilidade binária tem uma consequencia que muitos programadores não conhece : O ID (GUID) da interface default do component B muda. Ele mantém o ID antigo, mas passa a ter também um novo.

Imagine nesse cenário que a empresa possui um ambiente de desenvolvimento e um para homologação e que no momento os componentes estão funcionando em ambos os ambientes. Se o componente B é recompilado e reinserido no ambiente de homologação ele ganha um novo ID de interface, mas mantém o antigo. Assim sendo, o componente A que encontra-se no ambiente de homologação e que só conhece o ID de interface antigo ainda consegue acessa-lo, porém se o componente A em desenvolvimento for recompilado, seu novo executável (dll) passará a utilizar o novo ID de interface do componente B.

Imaginemos que mais uma vez o componente B foi atualizado em desenvolvimento, mas não foi passado para homologação. O componente A também foi atualizado em desenvolvimento, recompilado, e resolveu-se passa-lo para homologação.
Resultado : Por ter sido recompilado, o componente A aponta para o ID de interface do componente B mais atualizado. Porém ao ser inserido no ambiente de homologação o componente A encontrará um componente B que não possui essa interface. Consequentemente teremos uma falha no relacionamento entre o componente A e o componente B.

Resumindo : Se o componente A for compilado fazendo references para uma versão mais antiga do componente B, ele pode ser perfeitamente utilizado com a versão mais nova, pois esta guarda o ID de interface antigo. Mas se o componente A for compilado com uma versão mais nova do componente B, mesmo que não utilize nenhum recurso novo ele não pode ser utilizado com uma versão mais antiga, pois guardou o ID da nova interface. E tudo isso acontece mesmo com a compatibilidade binária estando sempre marcada.


Um recurso mínimo que precisamos para conseguir gerenciar este ambiente é poder identificar se duas DLLs de versões diferentes mantém ou não a compatibilidade binária.

Para fazer isso precisaremos acessar a type Library dessas DLLs e comparar o número de versões de interface que elas possuem e o GUID da última interface da DLL mais antiga com a equivalente na DLL mais nova.


Mas como fazer isso ? Simples : Temos a disposição uma biblioteca COM chamada Type Library Information que nos permite analisar o conteúdo da Type Library de um componente e consequentemente comparar seus IDs de interface.

Em primeiro lugar vamos desenhar a interface gráfica : Precisaremos de duas textbox, para que o usuário indique os 2 arquivos a serem comparados. Precisaremos de dois botões, um para cada textbox, para que o usuário possa clicar e abrir uma tela de navegação nos arquivos em disco para apontar para os arquivos. Consequentemente precisamos também de um comomdialog para produzir esse efeito.

Além disso teremos duas listbox nas quais o conteúdo das type librarys deverá ser carregado e um botão comparar. O usuário seleciona uma classe em cada listbox e pede para compararmos o ID de sua interface default.

É necessário fazer o references (project->References) para a biblioteca Type Library Information antes de começar a produzir o código. Vamos primeiro criar uma sub chamada perguntarArquivo que utilize o commondialog para permitir o usuário informar quais dlls quer comparar :


Private Sub PerguntarArquivo(t    As TextBox)
   On Error GoTo cancelou
   dlg.ShowOpen
   t.Text = dlg.FileName
   Exit Sub
   cancelou:
   t.Text = ""
End Sub


Até aqui, nada novo. A sub recebe uma textbox por parâmetro para que seja possível reutiliza-la nas duas escolhas de arquivo. Vamos então montar o código dos botões de escolha de arquivo :


   Dim tliAPP As New TLI.TLIApplication
   Dim lib1 As TypeLibInfo
   Dim lib2 As TypeLibInfo
Private Sub cmdCarregar1_Click()
   Dim i As CoClassInfo
 PerguntarArquivo txtArquivo1
   Set lib1 = tliAPP.TypeLibInfoFromFile(txtArquivo1)
   lstLib1.Clear
   
   For Each i In lib1.CoClasses
   lstLib1.AddItem i.Name
   Next
   
   End Sub
Private Sub cmdCarregar2_Click()
   Dim i As CoClassInfo
 PerguntarArquivo txtarquivo2
   Set lib2 = tliAPP.TypeLibInfoFromFile(txtarquivo2)
   lstLib2.Clear
   
   For Each i In lib2.CoClasses
   lstLib2.AddItem i.Name
   Next
End Sub


Após chamar a sub de escolha de arquivo, a Type Library contida no arquivo é carregada através do método TypeLibInfoFromFile. Então utilizamos um for/each na coleção coClasses, que contém as classes desse componente, para podermos inserir na listbox o nome das classes existentes na DLL.

O próximo passo é o botão comparar. Observe que deixamos os objetos lib1 e lib2 carregados com as referidas type librarys (TypelibInfo) :

Private Sub cmdComparar_Click()
   Dim a As Integer
if lstlib1.listindex=-1    or lstlib2.listindex=-1 then
   msgbox "Selecione as classes antes"
   exit sub
   end if
If lib1.TypeInfoCount >    lib2.TypeInfoCount Then
   If lib2.TypeInfos(lib2.TypeInfoCount - 1).Interfaces(1).Guid = lib1.GetTypeInfo(lib2.TypeInfos(lib2.TypeInfoCount    - 1).Name).Interfaces(1).Guid Then
        MsgBox "As classes possuem compatibilidade binária"
        MsgBox "Porém a primeira classe possui " & lib1.TypeInfoCount    & " versões de interface enquanto que a segunda possui apenas    " & lib2.TypeInfoCount
        MsgBox "Isso significa que componentes fazendo references para a 2a podem    utilizar a primeira, mas componentes fazendo references para a 1a não    podem utilizar a 2a"
   Else
        MsgBox "As classes não possuem compatibilidade binária"
   End If
ElseIf lib1.TypeInfoCount < lib2.TypeInfoCount Then
   If lib1.TypeInfos(lib1.TypeInfoCount - 1).Interfaces(1).Guid = lib2.GetTypeInfo(lib1.TypeInfos(lib1.TypeInfoCount    - 1).Name).Interfaces(1).Guid Then
       MsgBox "As classes possuem compatibilidade binária"
       MsgBox "Porém a segunda classe possui " & lib2.TypeInfoCount    & " versões de interface enquanto que a primeira possui apenas    " & lib1.TypeInfoCount
       MsgBox "Isso significa que componentes fazendo references para a 1a podem    utilizar a segunda, mas componentes fazendo references para a 2a não    podem utilizar a 1a"
   Else
       MsgBox "As classes não possuem compatibilidade binária"
   End If
Else
   If lib1.CoClasses(1).Interfaces(1).Guid = lib2.CoClasses(1).Guid Then
        MsgBox "As classes possuem total compatibilidade binária"
   Else
        MsgBox "As classes não possuem compatibilidade binária"
   End If
End If
   
End Sub

Primeiro o botão testa se existem itens selecionados em cada listbox. Depois faz a comparação. Observe que o código primeiramente identifica qual DLL é mais recente, comparando o número de interfaces existentes. Depois faz a comparação do GUID da última interface da dll mais antiga (a que tem menos interfaces) com o GUID da interface equivalente na DLL mais nova.

Se tiverem o mesmo número de interfaces fica até mais fácil, basta comparar os GUIDs mais recentes. A aplicação aproveita ainda para fornecer MSGBOX detalhados indicando em que casos componentes/aplicações que usarem estas DLLs funcionarão e em que casos não.


Dennes Torres
MCSD,MCSE,MCDBA


� Búfalo Informática, Treinamento e Consultoria - Rua Álvaro Alvim, 37 Sala 920 - Cinelândia - Rio de Janeiro / RJ
Tel.: (21)2262-1368 (21) 9240-5134 (21) 9240-7281 e-Mail:
contato@bufaloinfo.com.br