Segmentação de 32 bits e 64 bits com o Visual Studio na mesma solução / projeto

Eu tenho um pequeno dilema sobre como configurar o meu visual studio para multi-targeting.

Background: c # .NET v2.0 com p / invocando em DLL de terceiros de 32 bits, SQL compact v3.5 SP1, com um projeto de instalação. No momento, o destino da plataforma é definido como x86 para que possa ser executado no Windows x64.

A empresa de terceiros acabou de lançar versões de 64 bits de suas DLLs e eu quero construir um programa dedicado de 64 bits.

Isso levanta algumas questões para as quais ainda não tenho respostas. Eu quero ter exatamente a mesma base de código. Devo construir com referências ao conjunto de 32 bits de DLLs ou DLLs de 64 bits. (Ambos os terceiros e o SQL Server Compact)

Isso pode ser resolvido com dois novos conjuntos de configurações (Debug64 e Release64)?

Devo criar dois projetos de configuração separados (projetos std. Visual studio, sem Wix ou qualquer outro utilitário) ou isso pode ser resolvido dentro do mesmo .msi?

Quaisquer ideias e / ou recomendações seriam bem-vindas.

Sim, você pode segmentar x86 e x64 com a mesma base de código no mesmo projeto. Em geral, as coisas simplesmente funcionarão se você criar as configurações de solução corretas no VS.NET (embora P / Invoke para DLLs totalmente não gerenciadas provavelmente exigirá algum código condicional): os itens que eu achei que requerem atenção especial são:

  • Referências a assemblies gerenciados externos com o mesmo nome, mas sua própria densidade específica (isso também se aplica a assemblies de interoperabilidade COM)
  • O pacote MSI (que, como já foi observado, precisará ser direcionado para x86 ou x64)
  • Quaisquer ações personalizadas baseadas no .NET Installer Class no seu pacote MSI

O problema de referência de assembly não pode ser resolvido inteiramente dentro do VS.NET, pois ele só permitirá que você adicione uma referência com um nome a um projeto uma vez. Para solucionar esse problema, edite o arquivo de projeto manualmente (no VS, clique com o botão direito do mouse no arquivo de projeto no Solution Explorer, selecione Unload Project, clique com o botão direito do mouse novamente e selecione Edit). Depois de adicionar uma referência, digamos, à versão x86 de um assembly, o arquivo do seu projeto conterá algo como:

 C:\path\to\x86\DLL  

Embrulhe essa tag de referência dentro de uma tag ItemGroup indicando a configuração da solução a que se aplica, por exemplo:

  ....  

Em seguida, copie e cole a tag ItemGroup inteira e edite-a para conter os detalhes da DLL de 64 bits, por exemplo:

   C:\path\to\x64\DLL   

Depois de recarregar seu projeto no VS.NET, o diálogo Assembly Reference ficará um pouco confuso com essas mudanças, e você poderá encontrar alguns avisos sobre os assemblies com o processador de destino incorreto, mas todas as suas compilações funcionarão bem.

Resolver o problema do MSI é o próximo passo, e infelizmente isso exigirá uma ferramenta que não seja o .NET: Eu prefiro o Instalador Avançado da Caphyon para esse propósito, pois ele puxa o truque básico envolvido (criar um MSI comum, assim como 32 bits). e MSIs específicos de 64 bits, e usar um iniciador de instalação do .EXE para extrair a versão correta e fazer os ajustes necessários em tempo de execução) muito, muito bem.

Você provavelmente pode obter os mesmos resultados usando outras ferramentas ou o conjunto de ferramentas XML do Windows Installer (WiX) , mas o Instalador Avançado torna as coisas tão fáceis (e é bastante acessível) que eu nunca vi alternativas.

No entanto, uma coisa que você ainda pode exigir o WiX, mesmo quando estiver usando o Advanced Installer, é para as ações personalizadas da Classe do .NET Installer. Embora seja trivial especificar determinadas ações que devem ser executadas apenas em determinadas plataformas (usando as condições de execução VersionNT64 e NOT VersionNT64, respectivamente), as ações personalizadas AI incorporadas serão executadas usando o Framework de 32 bits, mesmo em máquinas de 64 bits .

Isso pode ser corrigido em uma versão futura, mas por enquanto (ou ao usar uma ferramenta diferente para criar seus MSIs que tenham o mesmo problema), você pode usar o suporte de ação personalizada gerenciada do WiX 3.0 para criar DLLs de ação com a densidade adequada será executado usando o Framework correspondente.


Editar: a partir da versão 8.1.2, o Advanced Installer suporta corretamente ações personalizadas de 64 bits. Desde a minha resposta original, o seu preço aumentou um pouco, infelizmente, mesmo que ainda seja um valor extremamente bom quando comparado ao InstallShield e à sua laia …


Edit: Se suas DLLs estiverem registradas no GAC, você também pode usar as tags de referência padrão dessa maneira (SQLite como um exemplo):

       

A condição também é reduzida para todos os tipos de construção, release ou debug e apenas especifica a arquitetura do processador.

Digamos que você tenha as DLLs construídas para as duas plataformas e elas estejam no seguinte local:

 C:\whatever\x86\whatever.dll C:\whatever\x64\whatever.dll 

Você só precisa editar seu arquivo .csproj:

 C:\whatever\x86\whatever.dll 

Para isso:

 C:\whatever\$(Platform)\whatever.dll 

Você deve, então, ser capaz de construir seu projeto visando ambas as plataformas, e o MSBuild procurará no diretório correto para a plataforma escolhida.

Não tenho certeza da resposta total à sua pergunta – mas pensei em apontar um comentário na seção Informações Adicionais da página de download do SQL Compact 3.5 SP1, já que você está olhando para x64 – espero que ajude.

Devido a alterações no SQL Server Compact SP1 e suporte adicional à versão de 64 bits, os ambientes de modo misto e instalado centralmente da versão de 32 bits do SQL Server Compact 3.5 e da versão de 64 bits do SQL Server Compact 3.5 SP1 podem criar o que parece ser intermitente problemas. Para minimizar o potencial de conflitos e habilitar a implantação neutra em plataforma dos aplicativos cliente gerenciados, a instalação central da versão de 64 bits do SQL Server Compact 3.5 SP1 usando o arquivo Windows Installer (MSI) também requer a instalação da versão de 32 bits do SQL Server. Arquivo Compact 3.5 SP1 MSI. Para aplicativos que exigem apenas 64 bits nativos, a implantação privada da versão de 64 bits do SQL Server Compact 3.5 SP1 pode ser utilizada.

Eu li isso como “include os arquivos SQLCE de 32 bits , bem como os arquivos de 64 bits” se distribuindo para clientes de 64 bits.

Torna a vida interessante, eu acho .. devo dizer que eu amo o “o que parece ser problemas intermitentes” linha … soa um pouco como “você está imaginando coisas, mas apenas no caso, faça isso …”

Quanto à sua última pergunta. Muito provavelmente você não pode resolver isso dentro de um único MSI. Se você estiver usando pastas de registro / sistema ou qualquer coisa relacionada, o próprio MSI deve estar ciente disso e você deve preparar um MSI de 64 bits para instalar corretamente na máquina de 32 bits.

Existe a possibilidade de você poder tornar seu produto instalado como um aplicativo 32 e ainda ser capaz de executá-lo como um de 64 bits, mas acho que isso pode ser difícil de alcançar.

Dito isto, você deve ser capaz de manter uma única base de código para tudo. No meu atual local de trabalho, conseguimos fazê-lo. (mas levou alguns malabarismos para fazer tudo tocar juntos)

Espero que isto ajude. Aqui está um link para algumas informações relacionadas a problemas de 32/64 bits: http://blog.typemock.com/2008/07/registry-on-windows-64-bit-double-your.html

Se você usar ações personalizadas escritas no .NET como parte do seu instalador MSI, você terá outro problema.

O ‘shim’ que executa essas ações personalizadas é sempre de 32 bits, então sua ação personalizada também será executada 32 bits, apesar de qual destino você especificar.

Mais informações e alguns movimentos ninja para se locomover (basicamente mude o MSI para usar a versão de 64 bits deste shim)

Construindo um MSI no Visual Studio 2005/2008 para trabalhar em um SharePoint 64

Ações personalizadas gerenciadas de 64 bits com o Visual Studio

Você pode gerar duas soluções de maneira diferente e mesclá-las depois! Eu fiz isso para o VS 2010. e funciona. Eu tinha 2 soluções diferentes geradas pelo CMake e as fundei

Você pode usar uma condição para um ItemGroup para as referências de dll no arquivo de projeto.
Isso fará com que o visual studio volte a verificar a condição e as referências sempre que você alterar a configuração ativa.
Basta adicionar uma condição para cada configuração.

Exemplo:

    ..\DLLName.dll   {AAAAAA-000000-BBBB-CCCC-TTTTTTTTTT} MyOtherProject   

Uma compilation .Net com dependencies x86 / x64

Enquanto todas as outras respostas dão a você uma solução para fazer Builds diferentes de acordo com a plataforma, dou a você a opção de ter apenas a configuração “AnyCPU” e fazer uma compilation que funcione com suas dlls x86 e x64.

Você tem que escrever algum código de encanamento para isso. Eu não consegui fazer isso funcionar com app.config. Se alguém souber uma maneira de resolvê-lo via app.config, eu realmente gostaria de saber.

Resolução de corrigir x86 / x64-dlls em tempo de execução

Passos:

  1. Use AnyCPU no csproj
  2. Decida se você faz referência apenas às dlls x86 ou x64 em seus csprojs. Adapte as configurações do UnitTests às configurações de arquitetura escolhidas. É importante para depurar / executar os testes dentro do VisualStudio.
  3. Em propriedades de referência, defina Copy Local & Specific Version para false
  4. Livre-se dos avisos de arquitetura adicionando esta linha ao primeiro PropertyGroup em todos os seus arquivos csproj nos quais você faz referência a x86 / x64: None
  5. Adicione este script postbuild ao seu projeto de boot, use e modifique os caminhos deste script sp que copia todos os seus x86 / x64 dlls em subpastas correspondentes de sua construção bin \ x86 \ bin \ x64 \

    xcopy /E /H /R /Y /I /D $(SolutionDir)\YourPathToX86Dlls $(TargetDir)\x86 xcopy /E /H /R /Y /I /D $(SolutionDir)\YourPathToX64Dlls $(TargetDir)\x64

    -> Quando você iniciaria a aplicação agora, você obtém uma exceção que a assembly não pôde ser encontrada.

  6. Registre o evento AssemblyResolve logo no início do ponto de input do seu aplicativo

     AppDomain.CurrentDomain.AssemblyResolve += TryResolveArchitectureDependency; 

    com este método:

     ///  /// Event Handler for AppDomain.CurrentDomain.AssemblyResolve ///  /// The app domain /// The resolve event args /// The architecture dependent assembly public static Assembly TryResolveArchitectureDependency(object sender, ResolveEventArgs resolveEventArgs) { var dllName = resolveEventArgs.Name.Substring(0, resolveEventArgs.Name.IndexOf(",")); var anyCpuAssemblyPath = $".\\{dllName}.dll"; var architectureName = System.Environment.Is64BitProcess ? "x64" : "x86"; var assemblyPath = $".\\{architectureName}\\{dllName}.dll"; if (File.Exists(assemblyPath)) { return Assembly.LoadFrom(assemblyPath); } return null; } 
  7. Se você tiver testes de unidade, faça um TestClass com um Method que tenha um AssemblyInitializeAttribute e também registre o TryResolveArchitectureDependency-Handler acima. (Isso não será executado às vezes se você executar testes únicos no Visual Studio, as referências serão resolvidas não a partir do escaninho UnitTest. Portanto, a decisão na etapa 2 é importante.)

Benefícios:

  • Uma instalação / construção para ambas as plataformas

Inconvenientes: – Nenhum erro em tempo de compilation quando dlls x86 / x64 não correspondem. – Você ainda deve executar o teste nos dois modos!

Opcionalmente, crie um segundo executável exclusivo para a arquitetura x64 com o Corflags.exe no script postbuild

Outras variantes a serem testadas: – Você não precisaria do manipulador de events AssemblyResolve se garantir que as dlls sejam copiadas na sua pasta binária no início (Evaluate Process architecture -> mova dlls correspondentes de x64 / x86 para a pasta bin e vice-versa). – No Installer, avalie a arquitetura e exclua os binários para uma arquitetura incorreta e mova os da direita para a pasta bin.