Dirigido tanto a 32 bits como a 64 bits con Visual Studio en la misma solución / proyecto


Tengo un pequeño dilema sobre cómo configurar mis compilaciones de visual studio para multi-targeting.

Background: c#. NET v2.0 con p/invocación en DLL de 32 bits de terceros, SQL compact v3.5 SP1, con un proyecto de configuración. En este momento, el objetivo de la plataforma está configurado en x86 para que se pueda ejecutar en Windows x64.

La 3rd party company acaba de lanzar versiones de 64 bits de sus DLL y quiero construir un programa dedicado de 64 bits.

Esto plantea algunas preguntas que no tengo las respuestas hasta ahora. Quiero tener exactamente el mismo código base. Debo construir con referencias al conjunto de DLL de 32 bits o DLL de 64 bits. (Tanto 3rd party como SQL Server Compact)

¿Se puede resolver esto con 2 nuevos conjuntos de configuraciones (Debug64 y Release64) ?

Debo crear 2 proyectos de instalación separados(std. proyectos de visual studio, sin Wix o cualquier otra utilidad), o se puede resolver dentro de la misma .msi?

Cualquier idea y/o recomendación sería bienvenida.

Author: Magnus Johansson, 2008-09-28

8 answers

Sí, puede apuntar tanto a x86 como a x64 con la misma base de código en el mismo proyecto. En general, las cosas funcionarán si crea las configuraciones de solución correctas en VS.NET (aunque P/Invoke para archivos DLL completamente no administrados lo más probable es que requiera algún código condicional): los elementos que encontré que requieren atención especial son:

  • Referencias a ensamblados gestionados externos con el mismo nombre pero con su propio bitness específico (esto también se aplica a la interop COM asambleas)
  • El paquete MSI (que, como ya se ha señalado, tendrá que apuntar a x86 o x64)
  • Cualquier acción basada en clases del instalador de. NET personalizado en su paquete MSI

El problema de referencia del ensamblado no se puede resolver completamente dentro de VS.NET, ya que solo le permitirá agregar una referencia con un nombre dado a un proyecto una vez. Para solucionar esto, edite el archivo de proyecto manualmente (en VS, haga clic con el botón derecho en el Explorador de soluciones y seleccione Descargar proyecto, luego haga clic derecho de nuevo y seleccione Editar). Después de agregar una referencia a, por ejemplo, la versión x86 de un ensamblado, su archivo de proyecto contendrá algo como:

<Reference Include="Filename, ..., processorArchitecture=x86">
  <HintPath>C:\path\to\x86\DLL</HintPath>
</Reference>

Envuelve esa etiqueta de referencia dentro de una etiqueta ItemGroup que indica la configuración de la solución a la que se aplica, por ejemplo:

<ItemGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
   <Reference ...>....</Reference>
</ItemGroup>

Luego, copie y pegue toda la etiqueta ItemGroup y edítela para que contenga los detalles de su DLL de 64 bits, por ejemplo:

<ItemGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
  <Reference Include="Filename, ..., processorArchitecture=AMD64">
     <HintPath>C:\path\to\x64\DLL</HintPath>
   </Reference>
</ItemGroup>

Después de recargar su proyecto en VS.NET, el diálogo de referencia del Ensamblado esté un poco confundido por estos cambios, y puede encontrar algunas advertencias sobre ensamblados con el procesador de destino incorrecto, pero todas sus compilaciones funcionarán bien.

Resolver el problema de MSI es lo siguiente, y desafortunadamente esto requerirá un non-VS.NET herramienta: Prefiero el Instalador avanzado de Caphyon para ese propósito, ya que saca el truco básico involucrado (crear un MSI común, así como MSI específicos de 32 bits y 64 bits, y usar un .EXE setup launcher para extraer el versión correcta y hacer las correcciones necesarias en tiempo de ejecución) muy, muy bien.

Probablemente puedas lograr los mismos resultados usando otras herramientas o el conjunto de herramientas Windows Installer XML (WiX) , pero Advanced Installer hace las cosas tan fáciles (y es bastante asequible) que nunca he mirado alternativas.

Una cosa que puede todavía requiere WiX, aunque, incluso cuando se utiliza el Instalador avanzado, es para las acciones personalizadas de su clase de instalador.NET. Aunque es trivial para especificar ciertas acciones que solo deben ejecutarse en ciertas plataformas (utilizando las condiciones de ejecución VersionNT64 y NO VersionNT64, respectivamente), las acciones personalizadas de IA integradas se ejecutarán utilizando el marco de trabajo de 32 bits, incluso en máquinas de 64 bits.

Esto puede arreglarse en una versión futura, pero por ahora (o cuando use una herramienta diferente para crear su MSI que tenga el mismo problema), puede usar el soporte de acción personalizada administrada de WiX 3.0 para crear DLL de acción con la bitness adecuada que se ejecutará utilizando el Marco correspondiente.


Editar: a partir de la versión 8.1.2, el Instalador avanzado soporta correctamente acciones personalizadas de 64 bits. Desde mi respuesta original, su precio ha aumentado bastante, desafortunadamente, a pesar de que sigue siendo extremadamente bueno en comparación con InstallShield y su clase...


Editar: Si sus DLL están registrados en el GAC, también puede usar las etiquetas de referencia estándar de esta manera (SQLite como ejemplo):

<ItemGroup Condition="'$(Platform)' == 'x86'">
    <Reference Include="System.Data.SQLite, Version=1.0.80.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=x86" />
</ItemGroup>
<ItemGroup Condition="'$(Platform)' == 'x64'">
    <Reference Include="System.Data.SQLite, Version=1.0.80.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=AMD64" />
</ItemGroup>

El la condición también se reduce a todos los tipos de compilación, liberación o depuración, y solo especifica la arquitectura del procesador.

 80
Author: mdb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-10 04:01:27

Digamos que tienes la compilación de DLL para ambas plataformas, y están en la siguiente ubicación:

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

Simplemente necesita editar su .archivo csproj de esto:

<HintPath>C:\whatever\x86\whatever.dll</HintPath>

A esto:

<HintPath>C:\whatever\$(Platform)\whatever.dll</HintPath>

Entonces debería ser capaz de construir su proyecto dirigido a ambas plataformas, y MSBuild buscará en el directorio correcto para la plataforma elegida.

 26
Author: Tim Booker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-02-20 16:51:38

No estoy seguro de la respuesta total a su pregunta, pero pensé que podría señalar un comentario en la sección de Información Adicional de la página de descarga SQL Compact 3.5 SP1 viendo que está mirando x64, espero que ayude.

Debido a cambios en SQL Server Compact SP1 y versión adicional de 64 bits soporte, instalado centralmente y mixto entornos de modo de versión de 32 bits de SQL Server Compact 3.5 y 64 bits versión de SQL Server Compact 3.5 SP1 puede crear lo que parece ser problemas intermitentes. Para minimizar el potencial de conflictos, y para permitir implementación neutral de la plataforma aplicaciones del cliente, centralmente instalación de la versión de 64 bits de SQL Server Compact 3.5 SP1 usando el Archivo de Windows Installer (MSI) también requiere instalar la versión de 32 bits de SQL Server Compact 3.5 SP1 MSI file. Para aplicaciones que solo requerir nativo de 64 bits, privado implementación de la versión de 64 bits de SQL Server Compact 3.5 SP1 puede ser utilizados.

Leo esto como "incluir los archivos SQLCE de 32 bits así como los archivos de 64 bits" si se distribuye para clientes de 64 bits.

Hace la vida interesante, supongo.. debo decir que me encanta la línea "lo que parece ser problemas intermitentes"... suena un poco como " estás imaginando cosas, pero por si acaso, haz esto..."

 1
Author: gleng,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-28 13:20:33

Con respecto a su última pregunta. Lo más probable es que no pueda resolver esto dentro de un solo MSI. Si está utilizando carpetas de registro / sistema o algo relacionado, el propio MSI debe ser consciente de esto y debe preparar un MSI de 64 bits para instalarlo correctamente en una máquina de 32 bits.

Existe la posibilidad de que usted puede hacer que el producto instalado como una aplicación de 32 ti y todavía ser capaz de hacer que se ejecute como 64 bits uno, pero creo que puede ser algo difícil de lograr.

Dicho esto creo que debería ser capaz de mantener una única base de código para todo. En mi actual lugar de trabajo lo hemos conseguido. (pero se necesitaron algunos malabares para hacer que todo jugara junto)

Espero que esto ayude. Aquí hay un enlace a información relacionada con problemas de 32/64 bits: http://blog.typemock.com/2008/07/registry-on-windows-64-bit-double-your.html

 0
Author: Lior Friedman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-28 13:29:03

Si utiliza Acciones personalizadas escritas en.NET como parte de su instalador MSI, entonces tiene otro problema.

El 'shim' que ejecuta estas acciones personalizadas siempre es de 32 bits, luego tu acción personalizada también ejecutará 32 bits, a pesar del objetivo que especifiques.

Más información y algunos movimientos ninja para moverse (básicamente cambiar el MSI para usar la versión de 64 bits de esta cuña)

Creación de un MSI en Visual Studio 2005/2008 para trabajar en un SharePoint 64

64-bit Acciones personalizadas administradas con Visual Studio

 0
Author: Ryan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-26 15:29:06

Puede generar dos soluciones de manera diferente y combinarlas después! Hice esto para VS 2010. y funciona. Tuve 2 soluciones diferentes generadas por CMake y las fusioné

 0
Author: tejas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-08-01 17:11:40

Puede usar una condición para un ItemGroup para las referencias dll en el archivo de proyecto.
Esto hará que visual studio vuelva a comprobar la condición y las referencias cada vez que cambie la configuración activa.
Simplemente agregue una condición para cada configuración.

Ejemplo:

 <ItemGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
    <Reference Include="DLLName">
      <HintPath>..\DLLName.dll</HintPath>
    </Reference>
    <ProjectReference Include="..\MyOtherProject.vcxproj">
      <Project>{AAAAAA-000000-BBBB-CCCC-TTTTTTTTTT}</Project>
      <Name>MyOtherProject</Name>
    </ProjectReference>
  </ItemGroup>
 0
Author: Yochai Timmer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-11 14:23:52

Una compilación. Net con dependencias x86 / x64

Mientras que todas las demás respuestas le dan una solución para hacer diferentes Compilaciones de acuerdo con la plataforma, le doy una opción para tener solo la configuración "AnyCPU" y hacer una compilación que funcione con sus DLL x86 y x64.

Tienes que escribir algún código de fontanería para esto. No pude conseguir que esto funcione con la aplicación.config. Si alguien más conoce una manera de resolverlo a través de la aplicación.config Realmente me gustaría saber.

Resolución de dlls x86/x64 correctos en tiempo de ejecución

Pasos:

  1. Use AnyCPU en csproj
  2. Decida si solo hace referencia a las DLL x86 o x64 en sus csprojs. Adapte la configuración de UnitTests a la configuración de arquitectura que haya elegido. Es importante para depurar / ejecutar las pruebas dentro de VisualStudio.
  3. On Reference-Properties set Copiar local & Versión específica a falso
  4. Deshazte de las advertencias de arquitectura agregando esto alinee el primer PropertyGroup en todos sus archivos csproj donde hace referencia a x86 / x64: <ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
  5. Agregue este script postbuild a su proyecto de inicio, use y modifique las rutas de este script sp que copia todas sus DLL x86 / x64 en las subcarpetas correspondientes de su build 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

    } > Cuando iniciaría la aplicación ahora, obtendrá una excepción que la asamblea no pudo ser encontrada.

  6. Registrar el AssemblyResolve evento justo al comienzo del punto de entrada de su aplicación

    AppDomain.CurrentDomain.AssemblyResolve += TryResolveArchitectureDependency;
    

    Con este método:

    /// <summary>
    /// Event Handler for AppDomain.CurrentDomain.AssemblyResolve
    /// </summary>
    /// <param name="sender">The app domain</param>
    /// <param name="resolveEventArgs">The resolve event args</param>
    /// <returns>The architecture dependent assembly</returns>
    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. Si tiene pruebas unitarias, haga una TestClass con un Método que tenga un AssemblyInitializeAttribute y también registre el controlador de dependencia TryResolveArchitectureDependency anterior allí. (Esto no se ejecutará a veces si ejecuta pruebas individuales dentro de visual studio, las referencias no se resolverán desde el bin UnitTest. Por lo tanto, la decisión en el paso 2 es importante.)

Beneficios:

  • Una instalación / Compilación para ambas plataformas

Inconvenientes: - No hay errores en tiempo de compilación cuando las DLL x86/x64 no coinciden. - Todavía debe ejecutar la prueba en ambos modos!

Opcionalmente crear un segundo ejecutable que es exclusivo para la arquitectura x64 con Corflags.exe en postbuild script

Otras Variantes para probar: - Usted no necesitaría el controlador de eventos AssemblyResolve si se asegura de lo contrario que los archivos dll obtener copiado en su carpeta binaria al inicio (Evaluar arquitectura de proceso - > mover las DLL correspondientes de x64 / x86 a la carpeta bin y viceversa.) - En el instalador evaluar la arquitectura y eliminar los binarios para la arquitectura incorrecta y mover los correctos a la carpeta bin.

 0
Author: Felix Keil,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-03 09:57:24