Управляемый C++ и AnyCPU

У меня есть управляемая dll С++, на которую я ссылаюсь из проекта С#. Проект C# будет скомпилирован как AnyCPU. Есть ли способ скомпилировать 32-разрядную и 64-разрядную версию библиотеки Managed C++ dll, а затем указать проекту C# во время выполнения загрузить правильный вариант в зависимости от используемой архитектуры?


person Dirk Dastardly    schedule 02.05.2012    source источник


Ответы (2)


Хитрость в том, чтобы заставить 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.LoadFrom(assembly_directory + @"\x64\" + assembly_dll);
     }
     else
     {
            assembly = Assembly.LoadFrom(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 Ivan Krivyakov; 13.05.2017
comment
Спасибо Иван! Я ценю вашу поддержку:) - person Kevin Marshall; 14.05.2017
comment
Спасибо Иван за комментарий. Я думал о том, что вы сказали, не делая этого в производстве. Итак, я пытаюсь немного поучиться здесь :) Источник вашего комментария касается безопасности? Я понимаю, что это хак, но, насколько я знаю, это один из нескольких способов, которыми я знаю, как реализовать поддержку объявления C# AnyCPU из Managed C++. Единственный другой подход, о котором я знаю, - это использование PInvoke, который, я думаю, страдает от той же проблемы. Я прихожу к выводу, что правильный подход - решить проблему при установке. - person Kevin Marshall; 15.05.2017
comment
Использование преобразователя сборок для загрузки зависимостей в производственном приложении означает, что пользовательскую логику разрешения зависимостей необходимо будет добавить к каждому инструменту, который работает с вашим кодом: средам модульного тестирования, инструментам покрытия и т. д. В противном случае они не смогут найти все необходимые сборки. Поначалу эта проблема может показаться не такой уж большой проблемой, но она очень быстро становится очень раздражающей. Я работал в компании, вся схема управления версиями библиотек которой была основана на пользовательском распознавателе сборок; они боролись с этим в течение нескольких лет и, наконец, сдались, вернувшись к стандартной загрузке сборки .NET. - person Ivan Krivyakov; 18.05.2017
comment
На самом деле это не так. Логика разрешения зависимостей инкапсулирована в net dll. Таким образом, любой код C#, зависящий от сетевой dll, может использовать общедоступные объекты в сетевой dll, как и любая другая сетевая dll. - person Kevin Marshall; 04.08.2018
comment
Что вы подразумеваете под «логикой разрешения, инкапсулированной в сетевой dll»? Например. если вы загрузите его в nUnit, как вы скажете nUnit загрузить правильные зависимости? Подключить преобразователь сборки в классе настройки тестов сборки? Ну да ладно, но теперь вы хотите загрузить его в какой-то анализатор кода... Что тогда? Организация, в которой я работал, крупный инвестиционный банк, пыталась внедрить пользовательскую логику разрешения в масштабах всей компании, управляла ею несколько лет и в конце концов сдалась, так как настоящие неудобства возникали то тут, то там. - person Ivan Krivyakov; 05.08.2018
comment
Для протокола: мы используем этот метод в производстве уже около 5 лет. Я уверен, что есть сценарии, в которых это громоздко или проблематично, но мы обнаружили, что это достаточно простой, но надежный подход к разработке, модульному тестированию и развертыванию. И да, для модульного тестирования мы делаем именно так, как предлагает Иван, и подключаем наш собственный преобразователь сборки в методе инициализации теста. - person Darryl; 16.11.2018
comment
Преобразователь сборки инкапсулирован в AnyCPU.dll, поэтому весь клиентский код напрямую зависит только от интерфейса AnyCPU.dll. Если вы посмотрите на исходный код, который я предоставил, в AnyCPU.Test.Develop или AnyCPU.Test.Distribute нет кода разрешения сборки. Если в модульных тестах требуется код преобразователя, это предполагает, что зависимости тестируемого кода не полностью инкапсулированы вдали от клиента. - person Kevin Marshall; 10.12.2018
comment
Чтобы ответить на вопрос Ивана: ModelInitializer включает раннюю регистрацию метода распознавателя сборки, чтобы AnyCPU.dll мог разрешать свои собственные зависимости. - person Kevin Marshall; 10.12.2018

Я не знаю, как вы «ссылаетесь» на dll С++ (ссылка на сборку P/Invoke и .net), но в любом случае вы можете поменять местами две версии .dll во время установки.

person Ventsyslav Raikov    schedule 02.05.2012