Ориентация как на 32-битную, так и на 64-битную версию Visual Studio в одном решении/проекте.

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

Вопрос

У меня возникла небольшая дилемма: как настроить сборки Visual Studio для многоцелевого таргетинга.

Фон:c# .NET v2.0 с p/вызовом сторонних 32-битных DLL, SQL Compact v3.5 SP1, с проектом установки.На данный момент целевая платформа установлена ​​на x86, поэтому ее можно запускать в Windows x64.

Сторонняя компания только что выпустила 64-битные версии своих DLL, и я хочу создать специальную 64-битную программу.

Это поднимает некоторые вопросы, на которые я пока не получил ответов.Я хочу иметь ту же самую базу кода.Я должен построить со ссылками либо на 32-битный набор DLL, либо на 64-битный набор DLL.(Как сторонние, так и SQL Server Compact)

Можно ли решить эту проблему с помощью двух новых наборов конфигураций (Debug64 и Release64)?

Должен ли я создать 2 отдельных проекта установки (std.Visual Studio, без Wix или какой-либо другой утилиты), или это можно решить в рамках того же .msi?

Любые идеи и/или рекомендации будут приветствоваться.

Это было полезно?

Решение

Да, вы можете использовать одну и ту же базу кода как для x86, так и для x64 в одном проекте.В общем, все будет работать, если вы создадите правильные конфигурации решения в VS.NET (хотя P/Invoke для полностью неуправляемых DLL, скорее всего, потребует некоторого условного кода):предметы, которые, по моему мнению, требуют особого внимания:

  • Ссылки на внешние управляемые сборки с тем же именем, но с собственной конкретной разрядностью (это также относится к сборкам COM-взаимодействия).
  • Пакет MSI (который, как уже отмечалось, должен быть ориентирован либо на x86, либо на x64)
  • Любые пользовательские действия на основе классов установщика .NET в вашем пакете MSI.

Проблема со ссылкой на сборку не может быть полностью решена в VS.NET, поскольку она позволит вам добавить ссылку с заданным именем в проект только один раз.Чтобы обойти эту проблему, отредактируйте файл проекта вручную (в VS щелкните правой кнопкой мыши файл проекта в обозревателе решений, выберите «Выгрузить проект», затем еще раз щелкните правой кнопкой мыши и выберите «Изменить»).После добавления ссылки, скажем, на версию сборки x86, файл вашего проекта будет содержать что-то вроде:

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

Оберните этот тег Reference внутри тега ItemGroup, указывая конфигурацию решения, к которой он применяется, например:

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

Затем скопируйте и вставьте весь тег ItemGroup и отредактируйте его, чтобы он содержал сведения о вашей 64-битной DLL, например:

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

После перезагрузки проекта в VS.NET диалоговое окно «Ссылка на сборку» будет немного запутано из-за этих изменений, и вы можете столкнуться с некоторыми предупреждениями о сборках с неправильным целевым процессором, но все ваши сборки будут работать нормально.

Решение проблемы MSI будет следующим, и, к сожалению, это воля требуется инструмент, отличный от VS.NET:Я предпочитаю Кафиона Расширенный установщик для этой цели, поскольку он выполняет основной трюк (создайте общий MSI, а также специальные 32-битные и 64-битные MSI и используйте средство запуска установки .EXE для извлечения нужной версии и выполнения необходимых исправлений во время выполнения). ) очень-очень хорошо.

Вероятно, вы сможете добиться тех же результатов, используя другие инструменты или Набор инструментов Windows Installer XML (WiX), но Advanced Installer делает все настолько простым (и при этом вполне доступным), что я никогда особо не рассматривал альтернативы.

Одна вещь, которую ты может по-прежнему требуется WiX, хотя даже при использовании расширенного установщика он предназначен для пользовательских действий вашего класса установщика .NET.Хотя указать определенные действия, которые должны выполняться только на определенных платформах, тривиально (с использованием условий выполнения VersionNT64 и NOT VersionNT64 соответственно), встроенные специальные действия AI будут выполняться с использованием 32-битной платформы даже на 64-битных машинах. .

Это может быть исправлено в будущем выпуске, но на данный момент (или при использовании другого инструмента для создания MSI, который имеет ту же проблему), вы можете использовать поддержку управляемых пользовательских действий WiX 3.0 для создания библиотек DLL действий с правильной разрядностью, которая будет выполнен с использованием соответствующей платформы.


Редактировать:начиная с версии 8.1.2 Advanced Installer корректно поддерживает 64-битные дополнительные действия.К сожалению, с момента моего первоначального ответа его цена немного выросла, хотя по сравнению с InstallShield и ему подобными он по-прежнему очень выгоден...


Редактировать:Если ваши библиотеки DLL зарегистрированы в GAC, вы также можете использовать стандартные ссылочные теги таким образом (например, SQLite):

<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>

Условие также сводится ко всем типам сборки, выпуску или отладке, и просто определяет архитектуру процессора.

Другие советы

Допустим, у вас есть сборки DLL для обеих платформ, и они находятся в следующем месте:

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

Вам просто нужно отредактировать файл .csproj следующим образом:

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

К этому:

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

После этого вы сможете создать проект для обеих платформ, и MSBuild найдет каталог, соответствующий выбранной платформе.

Не уверен в полном ответе на ваш вопрос, но решил указать на комментарий в разделе «Дополнительная информация» Страница загрузки SQL Compact 3.5 SP1 видя, что вы смотрите на x64, надеюсь, это поможет.

Из-за изменений в SQL Server Compact SP1 и дополнительной 64-разрядной поддержки версий, центрально установленных и смешанных режима проблемы.Чтобы свести к минимуму потенциал для конфликтов и включить нейтральное развертывание платформы управляемых клиентских приложений, в центре 64-битной версии SQL Server Compact 3.5 SP1 с использованием файла Windows Installer (MSI) также требуется установка 32-разрядной версии SQL Server Compact 3.5 SP1 MSI -файл.Для приложений, которые требуют только нативного 64-битного, можно использовать частное развертывание 64-битной версии SQL Server Compact 3.5 SP1.

Я прочитал это как «включить 32-битные файлы SQLCE». а также 64-битные файлы» при распространении для 64-битных клиентов.

Думаю, жизнь становится интересной..Должен сказать, что мне нравится фраза «то, что кажется периодическими проблемами»…звучит примерно так: «Вы что-то воображаете, но на всякий случай сделайте это…»

Что касается вашего последнего вопроса.Скорее всего, вы не сможете решить эту проблему внутри одного MSI.Если вы используете папки реестра/системы или что-то подобное, сам MSI должен знать об этом, и вы должны подготовить 64-битный MSI для правильной установки на 32-битном компьютере.

Существует вероятность того, что вы можете установить свой продукт как 32-разрядное приложение и при этом иметь возможность запускать его как 64-разрядное, но я думаю, что этого может быть несколько сложно достичь.

при этом я думаю, что вы должны иметь возможность хранить единую базу кода для всего.На моем нынешнем месте работы нам удалось это сделать.(но потребовалось некоторое жонглирование, чтобы заставить все работать вместе)

Надеюсь это поможет.Вот ссылка на некоторую информацию, связанную с проблемами 32/64 бит:http://blog.typemock.com/2008/07/registry-on-windows-64-bit-double-your.html

Если вы используете дополнительные действия, написанные на .NET, как часть установщика MSI, у вас возникает другая проблема.

«Прокладка», которая запускает эти настраиваемые действия, всегда является 32-битной, тогда ваше настраиваемое действие также будет выполняться на 32 бита, независимо от того, какую цель вы укажете.

Дополнительная информация и некоторые приемы ниндзя (по сути, измените MSI на использование 64-битной версии этой прокладки)

Создание MSI в Visual Studio 2005/2008 для работы с SharePoint 64.

64-разрядные управляемые пользовательские действия с помощью Visual Studio

Вы можете сгенерировать два решения по-разному, а затем объединить их!Я сделал это для VS 2010.и это работает.У меня было два разных решения, созданных CMake, и я их объединил.

Вы можете использовать условие для Группа предметов для ссылок dll в файле проекта.
Это заставит Visual Studio перепроверять условие и ссылки всякий раз, когда вы меняете активную конфигурацию.
Просто добавьте условие для каждой конфигурации.

Пример:

 <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>

Одна сборка .Net с зависимостями x86/x64.

Хотя все остальные ответы дают вам возможность создавать разные сборки в зависимости от платформы, я даю вам возможность использовать только конфигурацию «AnyCPU» и создавать сборку, которая работает с вашими библиотеками dll x86 и x64.

Для этого вам нужно написать сантехнический код.Я не смог заставить это работать с app.config.Если кто-то еще знает способ решить эту проблему через app.config, мне бы очень хотелось знать.

Разрешение правильных библиотек x86/x64 во время выполнения

Шаги:

  1. Используйте AnyCPU в csproj
  2. Решите, ссылаетесь ли вы только на библиотеки x86 или x64 в своих csprojs.Адаптируйте настройки UnitTests к выбранным вами настройкам архитектуры.Это важно для отладки/запуска тестов внутри VisualStudio.
  3. При наборе ссылочных свойств Копировать локально & Конкретная версия к ЛОЖЬ
  4. Избавьтесь от предупреждений об архитектуре, добавив эту строку в первую строку. Группа свойств во всех ваших файлах csproj, где вы ссылаетесь на x86/x64:<ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
  5. Добавьте этот сценарий постсборки в свой стартовый проект, используйте и измените пути этого сценария sp, чтобы он копировал все ваши библиотеки dll x86/x64 в соответствующие подпапки вашего 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

    -> Когда вы начнете применение сейчас, вы получите исключение, что сборка не может быть найдена.

  6. Зарегистрируйте событие AssemblyResolve прямо в начале точки входа вашего приложения.

    AppDomain.CurrentDomain.AssemblyResolve += TryResolveArchitectureDependency;
    

    с помощью этого метода:

    /// <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. Если у вас есть модульные тесты, создайте TestClass с методом, который имеет атрибут AssemblyInitializeAttribute, а также зарегистрируйте там приведенный выше TryResolveArchitectureDependency-Handler.(Иногда это не будет выполняться, если вы запускаете отдельные тесты внутри Visual Studio, ссылки будут разрешаться не из корзины UnitTest.Поэтому решение на шаге 2 важно.)

Преимущества:

  • Одна установка/сборка для обеих платформ

Недостатки:— Отсутствие ошибок во время компиляции, когда библиотеки DLL x86/x64 не совпадают.- Вам все равно придется запускать тест в обоих режимах!

При необходимости создайте второй исполняемый файл, эксклюзивный для архитектуры x64, с помощью Corflags.exe в сценарии постсборки.

Другие варианты, которые стоит попробовать:- Вам не понадобится обработчик событий AssemblyResolve, если вы убедитесь, что DLLS копируется в вашей двоичной папке в начале (оценка архитектуры процесса -> Переместить соответствующие DLL из X64/x86 в папку Bin и обратно.) - в оценке архитектуры установщика и Удалите двоичные файлы для неправильной архитектуры и переместите правильные в папку бина.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top