Utilice condicionalmente la referencia de 32/64 bits al construir en Visual Studio


Tengo un proyecto que se construye en 32/64 bits y tiene dependencias correspondientes de 32/64 bits. Quiero ser capaz de cambiar configuraciones y tener la referencia correcta utilizada, pero no se como decirle a Visual Studio que use la dependencia apropiada para la arquitectura.

Tal vez estoy haciendo esto de la manera equivocada, pero quiero ser capaz de cambiar entre x86 y x64 en el menú desplegable de configuración, y que la DLL referenciada sea la bitness correcta.

Author: Holf, 2010-09-30

6 answers

Esto es lo que he hecho en un proyecto anterior, que requerirá la edición manual de la .archivo(s) csproj. También necesita directorios separados para los diferentes binarios, idealmente hermanos entre sí, y con el mismo nombre que la plataforma a la que se dirige.

Después de agregar las referencias de una sola plataforma al proyecto, abra el .csproj en un editor de texto. Antes del primer elemento <ItemGroup> dentro del elemento <Project>, agregue el siguiente código, que ayudará a determinar qué plataforma estás corriendo (y construyendo).

<!-- Properties group for Determining 64bit Architecture -->
<PropertyGroup>
  <CurrentPlatform>x86</CurrentPlatform>
  <CurrentPlatform Condition="'$(PROCESSOR_ARCHITECTURE)'=='AMD64' or '$(PROCESSOR_ARCHITEW6432)'=='AMD64'">AMD64</CurrentPlatform>
</PropertyGroup>

Luego, para las referencias específicas de su plataforma, realice cambios como los siguientes:

<ItemGroup>
  <Reference Include="Leadtools, Version=16.5.0.0, Culture=neutral, PublicKeyToken=9cf889f53ea9b907, processorArchitecture=x86">
    <SpecificVersion>False</SpecificVersion>
    <HintPath>..\..\Lib\Leadtools\$(CurrentPlatform)\Leadtools.dll</HintPath>
  </Reference>
  <Reference Include="Leadtools.Codecs, Version=16.5.0.0, Culture=neutral, PublicKeyToken=9cf889f53ea9b907, processorArchitecture=x86">
    <SpecificVersion>False</SpecificVersion>
    <HintPath>..\..\Lib\Leadtools\$(CurrentPlatform)\Leadtools.Codecs.dll</HintPath>
  </Reference>
  <Reference Include="Leadtools.ImageProcessing.Core, Version=16.5.0.0, Culture=neutral, PublicKeyToken=9cf889f53ea9b907, processorArchitecture=x86">
    <SpecificVersion>False</SpecificVersion>
    <HintPath>..\..\Lib\Leadtools\$(CurrentPlatform)\Leadtools.ImageProcessing.Core.dll</HintPath>
  </Reference>
  <Reference Include="System" />
  <Reference Include="System.Core" />
  <Reference Include="System.Data.Entity" />
  <!--  Other project references -->
</ItemGroup>

Tenga en cuenta el uso de la propiedad $(CurrentPlatform), que definimos anteriormente. En su lugar, podría usar condicionales para qué ensamblados incluir para qué plataforma. También puede necesitar:

  • Sustitúyanse los $(PROCESSOR_ARCHITEW6432) y $(PROCESSOR_ARCHITECTURE) por $(Platform) para considerar ÚNICAMENTE la plataforma objetivo de los proyectos
  • Alterar la lógica de determinación de la plataforma en orden para ser apropiado para la máquina actual, para que no esté construyendo / haciendo referencia a un binario de 64 bits para ejecutar en una plataforma de 32 bits.

Lo había escrito originalmente para un Wiki interno en el trabajo, sin embargo, lo he modificado y publicado el proceso completo en mi blog , si está interesado en las instrucciones detalladas paso a paso.

 94
Author: Hugo,
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-03-28 15:20:41

AFAIK, si su proyecto requiere referencias que son específicas de 32 bits o 64 bits (es decir, ensamblajes COM-interop), y no tiene interés en editar manualmente el .archivo csproj, entonces usted tendrá que crear proyectos separados de 32 bits y 64 bits.

Debo señalar que la siguiente solución no está probada, pero debería funcionar. Si está dispuesto a editar manualmente el .csproj archivo, entonces usted debe ser capaz de lograr el resultado deseado con un solo proyecto. El .el archivo csproj es solo un MSBuild script, así que para una referencia completa, mira aquí. Una vez que abra el .archivo csproj en un editor, busque los elementos <Reference>. Debería poder dividir estos elementos en 3 grupos de elementos distintos: referencias que no son específicas de la plataforma, referencias específicas de x86 y referencias específicas de x64.

Aquí hay un ejemplo que asume que su proyecto está configurado con plataformas de destino llamadas "x86" y "x64"

<!-- this group contains references that are not platform specific -->
<ItemGroup>
    <Reference Include="System" />
    <Reference Include="System.Core" />
    <!-- any other references that aren't platform specific -->
</ItemGroup>

<!-- x86 specific references -->
<ItemGroup Condition=" '$(Platform)' == 'x86' ">
    <Reference Include="MyComAssembly.Interop">
        <HintPath>..\..\lib\x86\MyComAssembly.Interop.dll</HintPath>
    </Reference>

    <!-- any additional x86 specific references -->
</ItemGroup>

<!-- x64 specific referneces -->
<ItemGroup Condition=" '$(Platform)' == 'x64' ">
    <Reference Include="MyComAssembly.Interop">
        <HintPath>..\..\lib\x64\MyComAssembly.Interop.dll</HintPath>
    </Reference>

    <!-- any additional x64 specific references -->
</ItemGroup>

Ahora, cuando configure la compilación de su proyecto / solución configuración para apuntar a la plataforma x86 o x64, debe incluir las referencias adecuadas en cada caso. Por supuesto, tendrás que jugar con los elementos <Reference>. Incluso puede configurar proyectos ficticios donde agregue las referencias x86 y x64, y luego simplemente copie los elementos <Reference> necesarios de esos archivos de proyecto ficticios a su archivo de proyecto "real".


Edit 1
Aquí hay un enlace a los elementos comunes del proyecto MSBuild, que accidentalmente dejé fuera de la publicación original: http://msdn.microsoft.com/en-us/library/bb629388.aspx

 52
Author: Justin Holzer,
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
2015-01-27 22:32:37

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>
 19
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:22:07

Estoy haciendo referencia a las DLL x86, ubicadas en, por ejemplo, \component\v3_NET4, en mi proyecto. Las DLL específicas para x86 / x64 se encuentran en subcarpetas llamadas "x86" y " x64 " resp.

Entonces estoy usando un script pre-build que copia los archivos DLL apropiados (x86/x64) en la carpeta referenciada, basado en Plat(platformName).

xcopy /s /e /y "$(SolutionDir)..\component\v3_NET4\$(PlatformName)\*" "$(SolutionDir)..\component\v3_NET4"

Funciona para mí.

 7
Author: Micke,
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-14 10:09:50

Me enfrenté al mismo problema y pasé bastante tiempo buscando una solución decente. La mayoría de las personas ofrecen la edición manual de los archivos de Visual Studio solution, lo cual es bastante tedioso, propenso a errores y confuso al explorar estos archivos editados en Visual Studio GUI después. Cuando ya me di por vencido, la solución surgió por sí misma. Es muy similar a lo que Micke recomienda en su respuesta anterior.

En account manager he creado dos destinos de compilación separados para plataformas x86 y x64, como de costumbre. A continuación, agregué una referencia al ensamblaje x86 a mi proyecto. En este punto, creo que el proyecto está configurado para x86 construir solamente y nunca construir para x64 configuración, a menos que voy a hacer la edición manual de la misma como lo sugirió Hugo anteriormente.

Después de un tiempo, finalmente olvidé la limitación y accidentalmente inicié la compilación de x64. Por supuesto, la construcción falló. Pero importante fue el mensaje de error que recibí. Mensaje de error dijo que el ensamblado nombrado exactamente como mi ensamblado x86 referenciado es falta en la carpeta destinada como destino de compilación x64 para mi solución.

Habiendo notado esto, he copiado manualmente el ensamblado x64 apropiado en este directorio. Gloria! Mi x64 construir milagrosamente tuvo éxito con el montaje adecuado encontrado y vinculado implícitamente. Era cuestión de minutos modificar mi solución para establecer un directorio de destino de compilación para el ensamblaje x64 en esta carpeta. Después de estos pasos, la solución se construye automáticamente para x86 y x64 sin ninguna edición manual de archivos MSBuild.

A resumen:

  1. Crear objetivos x86 y x64 en un solo proyecto
  2. Agregue todas las referencias de proyecto adecuadas a ensamblajes x86
  3. Establecer un directorio de destino de compilación común para todos los ensamblados x64
  4. En caso de que tenga ensamblados x64 listos, simplemente cópielos una vez en su directorio de destino de compilación x64

Después de completar estos pasos, su solución se compilará correctamente para configuraciones x86 y x64.

Esto funcionó para mí en Proyecto Visual Studio 2010.NET 4.0 C#. Evidentemente, se trata de una especie de comportamiento interno indocumentado de Visual Studio, que podría estar sujeto a cambios en las versiones de 2012, 2013 y 2015. Si alguien va a probar otras versiones, por favor comparta su experiencia.

 2
Author: Boris Zinchenko,
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
2015-09-04 08:33:46

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:54:13