Любой процессор, недоступный в решении C++/C#

У меня есть решение, содержащее C# и управляемые проекты C++. Он компилируется в платформе решения x64 и x86. Поскольку он управляется C ++, я хотел создать решение «Любой процессор» и избавиться от старых.

Я изменил настройки компоновщика проекта C++ на Force Safe IL Image как для x64, так и для x86.

Затем с помощью диспетчера конфигураций я создал новую платформу решения под названием «Любой процессор». Затем я добавил платформу проекта, также называемую Any CPU.

Я установил для всех проектов С# значение «Любой процессор», но для С++ я не могу этого сделать. Платформа проекта «Любой процессор» отсутствует в раскрывающемся списке, а также нет опции «Новый...».

VS относится к этому с пониманием, поэтому я оставил все как есть и начал сборку. К моему удивлению, полученная DLL (из проекта C++) была MSIL, хотя платформа для C++ была x64. То же самое происходит при компиляции x32, результирующая DLL находится в MSIL.

Что дает? Почему я не могу установить для проекта C++ значение «Любой процессор»?


person Frank Kaaijk    schedule 02.02.2015    source источник
comment
возможный дубликат Managed C++ и AnyCPU   -  person Christopher Painter    schedule 02.02.2015
comment
Я так не думаю, потому что полученная DLL из проекта C++ — это MSIL. Таким образом, нет необходимости делать «странные» вещи с загрузкой x64 или x86. Я просто не могу понять, почему я не могу скомпилировать Managed C++ как «любой процессор» (в конфигурации)   -  person Frank Kaaijk    schedule 02.02.2015
comment
Попытка объяснить, что конкретное название платформы совершенно не имеет значения, когда вы создаете код, который, как вы знаете, работает на любой платформе, — это геркулесова работа, которая никогда не выполнялась. Единственное, что имеет значение, это переопределение джиттера в проекте EXE.   -  person Hans Passant    schedule 02.02.2015
comment
@ChristopherPainter: это не дубликат этого сообщения. Тот, который вы предлагаете в качестве дубликата, обсуждает использование специфичных для платформы библиотек DLL C++/CLI, выбранных автоматически в соответствии с платформой. Здесь OP нужна сборка C++/CLI DLL, которая имеет те же характеристики, что и сборка C# AnyCPU. т.е. единая сборка, которая может работать на любой платформе.   -  person Peter Duniho    schedule 03.02.2015


Ответы (2)


Насколько мне известно, вы не можете создать тип проекта AnyCPU в Visual Studio для проекта C++/CLI. Однако вы можете настроить свой проект C++/CLI (под типом проекта "Win32"), чтобы он компилировался как чистый, безопасный MSIL без целевой платформы. Это позволит использовать вашу сборку C++/CLI DLL с проектом C# AnyCPU. т.е. на самом деле это «AnyCPU», хотя это не его фактическое имя в диспетчере конфигураций.

В настройках проекта "C/C++":

  • Поддержка общеязыковой среды выполнения: Safe MSIL Common Language RunTime Support (/clr:safe)

В настройках проекта "Linker":

  • Тип образа CLR: просто убедитесь, что для него явно не задано значение IJW или PURE.

Примечания:

  • При использовании «безопасного» типа проекта некоторые параметры компилятора и компоновщика, которые влияют на тип платформы, будут игнорироваться. т.е. вам не нужно проходить и устанавливать все для неспецифического типа платформы. Только выше. Но вы можете установить другие параметры на что-то подходящее, если вам от этого станет лучше. :)
  • «Безопасный» предотвратит использование указателей. Если это важный вопрос, видимо, можно обойтись, хотя и более сложным процессом. См. Создание чистой сборки MSIL из проекта C++/CLI? для подробностей.
  • Не забывайте, что по умолчанию Visual Studio создает проекты C#, которые, несмотря на то, что они являются «AnyCPU» и выполняются в 64-разрядной ОС, будут запускаться как 32-разрядный процесс. Это может скрыть проблемы несоответствия платформы, если зависимость является x86, а не чистым/безопасным MSIL, как предполагалось. Просто имейте в виду (вы можете контролировать это, сняв флажок «Предпочитать 32-разрядную версию» на странице свойств проекта «Сборка» проекта С#).
person Peter Duniho    schedule 03.02.2015
comment
Этот ответ согласуется с тем, что я вижу в решении. Мне не удалось найти какую-либо ссылку, например, в MSDN, которая объясняла бы, что пишет Питер, а именно, вы не можете создать тип проекта AnyCPU в Visual Studio для проекта C++/CLI. - person Frank Kaaijk; 03.02.2015
comment
В VS2015 Update 5 это генерирует предупреждение компилятора D9035, которое говорит нам, что мы действительно компилируем Managed C++, который устарел, и поддержка будет удалена в будущем выпуске (еще не пробовал 2017, возможно, этот ответ больше недействителен). Позор, потому что это действительно то, что мы хотим, профиль компилятора/компоновщика AnyCPU. - person Tony Wall; 04.05.2017
comment
Это неверный ответ, потому что, если вы генерируете только MSIL, вам все равно не следует писать код на C++. Если вы пишете программное обеспечение только с использованием .NET Framework и библиотек MSIL, то вы только усложняете задачу, пытаясь писать на C++. Единственное преимущество, которое я могу себе представить, возможно, связано с кодом PInvoke, но предупреждения и нестандартный/устаревший подход отталкивают меня от этого решения. - person Tony Wall; 04.05.2017

Чтобы функциональные возможности C++ могли использоваться dll C#, проект C++ должен создавать версии dll x86 и x64. Невозможно ссылаться только на dll x86 или x64 из dll C#, скомпилированного с параметром AnyCPU.

Хитрость в том, чтобы заставить dll AnyCPU играть с dll C++, заключается в том, чтобы во время выполнения убедиться, что сборка не может загрузить dll C++, а затем подписаться на событие AppDomain AssemblyResolve. Когда сборка пытается загрузить dll и терпит неудачу, ваш код имеет возможность определить, какую dll нужно загрузить.

Подписка на событие выглядит примерно так:

System.AppDomain.CurrentDomain.AssemblyResolve += Resolver;

Обработчик события выглядит примерно так:

System.Reflection.Assembly Resolver(object sender, System.ResolveEventArgs args)
{
     string assembly_dll = new AssemblyName(args.Name).Name + ".dll";
     string assembly_directory = "Parent directory of the C++ dlls";

     Assembly assembly = null;
     if(Environment.Is64BitProcess)
     {
            assembly = Assembly.LoadFile(assembly_directory + @"\x64\" + assembly_dll);
     }
     else
     {
            assembly = Assembly.LoadFile(assembly_directory + @"\x86\" + assembly_dll);
     }
     return assembly;
}

Я создал простой проект, демонстрирующий, как получить доступ к функциям C++ из dll AnyCPU.

https://github.com/kevin-marshall/Managed.AnyCPU

person Kevin Marshall    schedule 22.11.2016
comment
Спасибо, Тоби, я обновил свой ответ, надеюсь, он стал более информативным. - person Kevin Marshall; 22.11.2016