![]() |
||||||||
|
|
||||||||
| Gostou
da Página? Clique no botão abaixo para indicar esta página para um amigo! |
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.
© 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