O aplicativo não funciona com DLLs do VS 2008 SP1, a versão anterior funciona com versões RTM

StackOverflow https://stackoverflow.com/questions/59635

  •  09-06-2019
  •  | 
  •  

Pergunta

Desde a mudança do Visual Studio 6 para o Visual Studio 2008, temos usado MFC90.dll e msvc[pr]90.dlls junto com os arquivos de manifesto em uma configuração privada lado a lado para não nos preocuparmos com versões ou instalá-los no sistema.

Antes do SP1, isso funcionava bem (e ainda funciona bem em nossas máquinas de desenvolvedores).Agora que fizemos alguns testes pós-SP1, estou arrancando os cabelos desde ontem de manhã.

Primeiro, nosso script de instalação do NSIS extrai as DLLs e os arquivos de manifesto da pasta redist.Isso não estava mais correto, pois o aplicativo ainda está vinculado à versão RTM.

Então adicionei a definição para _BIND_TO_CURRENT_VCLIBS_VERSION=1 a todos os nossos projetos para que eles usem as DLLs do SP1 na pasta redist (ou subsequentes à medida que novos service packs forem lançados).Levei horas para encontrar isso.

Verifiquei novamente os arquivos de manifesto gerados na pasta de arquivos intermediários da compilação e eles listam corretamente as versões 9.0.30729.1 SP1.Verifiquei duas e três vezes dependendo de uma máquina limpa:tudo está vinculado às DLLs locais sem erros.

A execução do aplicativo ainda apresenta o seguinte erro:

O aplicativo falhou ao inicializar corretamente (0xc0150002).Clique em ok para encerrar o aplicativo.

Nenhuma das pesquisas que fiz no Google ou na Microsoft encontrou algo relacionado aos meus problemas específicos (mas há resultados desde 2005 com esta mensagem de erro).

Alguém teve algum problema semelhante com o SP1?

Opções:

  • Encontre o problema e corrija-o para que funcione como deveria (preferencial)
  • Instale o redist
  • desenterre as dlls RTM antigas e os arquivos de manifesto e remova o #define para usar os atuais.(Eu os tenho em uma versão anterior do instalador, já que a Microsoft os remove da sua pasta redist!)

Editar: Tentei reconstruir com a definição desativada (link para dlls RTM), e isso funciona desde que as dlls RTM estejam instaladas na pasta.Se as DLLs do SP1 forem inseridas, ocorrerá o seguinte erro:

c:\Arquivos de Programas\...\...\X.exe

Este aplicativo não foi iniciado porque a configuração do aplicativo está incorreta.A reinstalação do aplicativo pode resolver esse problema.

Ninguém mais teve que lidar com esse problema?

Editar: Só para rir, baixei e executei vcredist_x86.exe para VS2008SP1 em minha máquina de teste. Isto funciona.Com as DLLs do SP1.E meu aplicativo vinculado ao RTM.Mas NÃO em uma distribuição privada lado a lado que funcionava antes do SP1.

Foi útil?

Solução

Eu mesmo lutei contra esse problema na semana passada e me considero um especialista agora;)

Tenho 99% de certeza de que nem todas as DLLs e bibliotecas estáticas foram recompiladas com a versão SP1.Você precisa colocar

#define _BIND_TO_CURRENT_MFC_VERSION 1
#define _BIND_TO_CURRENT_CRT_VERSION 1

em todo projeto que você está usando.Para cada projeto de tamanho real, é muito fácil esquecer alguma pequena biblioteca que não foi recompilada.

Existem mais sinalizadores que definem a quais versões vincular;está documentado em http://msdn.microsoft.com/en-us/library/cc664727%28v=vs.90%29.aspx .Como alternativa às linhas acima, você também pode colocar

#define _BIND_TO_CURRENT_VCLIBS_VERSION 1

que será vinculado à versão mais recente de todas as bibliotecas VC (CRT, MFC, ATL, OpenMP).

Em seguida, verifique o que diz o manifesto incorporado.Baixe o Editor de Recursos XM: http://www.wilsonc.demon.co.uk/d10resourceeditor.htm.Abra todas as DLL e exe da sua solução.Procure em 'Manifesto do tema XP'.Verifique se o atributo 'versão' no lado direito é '9.0.30729.1'.Se for '9.0.21022', alguma biblioteca estática está extraindo o manifesto da versão antiga.

O que descobri é que, em muitos casos, ambos versões foram incluídas no manifesto.Isso significa que algumas bibliotecas usam a versão sp1 e outras não.

Uma ótima maneira de depurar quais bibliotecas não possuem as diretivas do pré-processador definidas:modifique temporariamente os cabeçalhos da sua plataforma para que a compilação pare quando tentar incorporar o manifesto antigo.Abra C:\Arquivos de Programas\Microsoft Visual Studio 9.0\VC\crt\include\crtassem.h.Procure a string '21022'.Nessa definição, coloque algo inválido (altere 'define' para 'blehbleh' ou algo assim).Dessa forma, quando você estiver compilando um projeto onde o _BIND_TO_CURRENT_CRT_VERSION o sinalizador do pré-processador não estiver definido, sua compilação será interrompida e você saberá que precisa adicioná-los ou certificar-se de que ele seja aplicado em todos os lugares.

Certifique-se também de usar o Dependency Walker para saber quais DLLs estão sendo extraídas.É mais fácil instalar uma cópia nova do Windows XP sem atualizações (apenas SP2) em uma máquina virtual.Dessa forma, você tem certeza de que não há nada na pasta SxS que está sendo usado em vez das DLLs lado a lado que você forneceu.

Outras dicas

Para compreender o problema, penso que é importante perceber que existem quatro números de versão envolvidos:

  • (A) A versão dos arquivos de cabeçalho VC para os quais o .exe é compilado.
  • (B) A versão do arquivo de manifesto incorporado na seção de recursos desse .exe.Por padrão, esse arquivo de manifesto é gerado automaticamente pelo Visual Studio.
  • (C) A versão dos .DLLs do VC (parte da montagem lado a lado) que você copia no mesmo diretório que o .exe.
  • (D) A versão dos arquivos de manifesto do VC (parte da montagem lado a lado) que você copia no mesmo diretório que o .exe.

Existem duas versões das DLLs do VC 2008 em execução:

  • v1:9.0.21022.8
  • v2:9.0.30729.4148

Para maior clareza, usarei a notação v1/v2.A tabela a seguir mostra uma série de situações possíveis:

Situation | .exe (A) | embedded manifest (B) | VC DLLs (C) | VC manifests (D)
-----------------------------------------------------------------------------
1         | v2       | v1                    | v1          | v1         
2         | v2       | v1                    | v2          | v2          
3         | v2       | v1                    | v2          | v1
4         | v2       | v2                    | v2          | v2

Os resultados dessas situações ao executar o .exe em uma instalação limpa do Vista SP1 são:

  • Situação 1:um pop-up é mostrado, dizendo:"O ponto de entrada do procedimento XYZXYZ não pôde ser localizado na biblioteca de vínculo dinâmico".

  • Situação 2:nada parece acontecer ao executar o .exe, mas o seguinte evento é registrado no "Visualizador de eventos/log do aplicativo" do Windows:

    Falha na geração do contexto de ativação para "C:\Path\file.exe".Erro no manifesto ou arquivo de política "C:\Path\Microsoft.VC90.CRT.MANIFEST" na linha 4.A identidade do componente encontrada no manifesto não corresponde à identidade do componente solicitado.A referência é Microsoft.VC90.CRT,processorArchitecture="x86",publicKeyToken="1fc8b3b9a1e18e3b",type="win32",version="9.0.21022.8".A definição é Microsoft

  • Situação 3:Tudo parece estar funcionando bem.Isso é Solução da remicles2.

  • Situação 4:isso é como deveria ser feito.Lamentavelmente, como Roel indica, pode ser bastante difícil de implementar.

Agora, a minha situação (e penso que é a mesma crashmstr's) é o número 1.O problema é que o Visual Studio, por um motivo ou outro, gera o código do cliente (A) para v2, mas por um motivo ou outro, gera um arquivo de manifesto v1 (B).Não tenho ideia de onde a versão (A) pode ser configurada.

Observação que toda esta explicação ainda está no contexto de assembleias privadas.

Atualizar:finalmente começo a entender o que está acontecendo.Aparentemente, O Visual Studio gera código do cliente (A) para v2 por padrão, ao contrário do que li em alguns blogs da Microsoft.A flag _BIND_TO_CURRENT_VCLIBS_VERSION seleciona apenas a versão no arquivo de manifesto gerado (B), mas esta versão será ignorada ao executar a aplicação.

Conclusão

Um .exe compilado pelo Visual Studio 2008 vincula-se às versões mais recentes das DLLs VC90 por padrão.Você pode use o sinalizador _BIND_TO_CURRENT_VCLIBS_VERSION para controlar qual versão das bibliotecas VC90 será gerada no arquivo de manifesto.Na verdade, isso evita a situação 2 em que você recebe a mensagem de erro "o manifesto não corresponde à identidade do componente solicitado".Também explica por que a situação 3 funciona bem, pois mesmo sem o sinalizador _BIND_TO_CURRENT_VCLIBS_VERSION o aplicativo está vinculado às versões mais recentes das DLLs do VC.

A situação é ainda mais estranha com assemblies públicos lado a lado, onde o vcredist foi executado, colocando as DLLs do VC 9.0 no diretório SxS do Windows.Mesmo que o arquivo de manifesto .exe indique que as versões antigas das DLLs devem ser usadas (este é o caso quando o sinalizador _BIND_TO_CURRENT_VCLIBS_VERSION não está definido), o Windows ignora este número de versão por padrão!Em vez disso, o Windows usará uma versão mais recente se estiver presente no sistema, exceto quando um "arquivo de configuração do aplicativo" é usado.

Sou o único que acha isso confuso?

Então resumindo:

  • Para assemblies privados, use o sinalizador _BIND_TO_CURRENT_VCLIBS_VERSION no projeto .exe e todos projetos .lib dependentes.
  • Para assemblies públicos, isso não é necessário, pois o Windows selecionará automaticamente a versão correta dos .DLLs do diretório SxS.

Acabei de me lembrar de outro truque que usei para descobrir quais bibliotecas estáticas estavam se comportando mal:'grep' através das bibliotecas estáticas para a string '21022'.NO ENTANTO, não use as ferramentas grep 'normais' como o wingrep porque elas não mostrarão essas strings (eles acham que é um arquivo binário e procuram a string bruta e não Unicode).Use o utilitário 'strings' do kit de recursos (agora no site Russinovich, eu acho).Esse irá percorrer os binários, ok.Então você deixa essas 'strings' percorrerem toda a sua árvore de origem e verá os arquivos binários (dlls e bibliotecas estáticas) que contêm referências ao manifesto errado (ou ao manifesto com a versão errada).

Outra boa ferramenta para visualizar manifestos exe e dll é Visualização do Manifesto, que apropriadamente não funcionará em uma instalação limpa do XP, porque isto depende de 9.0.21022.

Para sua terceira opção, você provavelmente encontrará as DLLs e manifestos para a versão 9.0.21022 no diretório C:\WINDOWS\WinSxS em sua máquina de desenvolvimento.Se puder, você pode configurar seu próprio diretório redist e instalar esses arquivos com seu aplicativo.

Como alternativa, você pode usar os 9.0.30729.1 fornecidos com o Visual Studio e forjar o manifesto instalado com seu aplicativo para informar que ele fornece as DLLs 9.0.21022, e não 9.0.30729.1.O vinculador de tempo de execução não parece se importar.Veja isso blog, que tem sido imensamente útil para resolver esses problemas, para obter mais informações.

Ambas as soluções alternativas corrigiram os problemas que tive ao implantar as DLLs como assemblies privados com o VS2008 Express.

A resposta de Roel é o caminho a seguir para sua primeira opção ("consertar corretamente"), mas se você depende de uma biblioteca que depende de 9.0.21022 (e seu manifesto, portanto, lista as duas versões), então a terceira opção pode ser a única muito bem se você não quiser executar vcredist_x86.exe.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top