Вот пример того, как мы делаем нечто подобное в родном приложении C ++.
Компилировать с /clr
. Вы можете сделать это для всего проекта или только для отдельных файлов C ++, но, насколько я помню, были сложности с выборочной работой, и мы просто сделали это для всего проекта. Также #include <vcclr.h>
, где это уместно.
Вам нужно будет узнать о доменах приложений . Главное, что вы загрузили сборку в домен, вы не можете выгрузить сборку, кроме как выгрузкой всего домена. Поскольку вы хотите загрузить сборку, запросить ее версию и затем отпустить ее, вы, вероятно, захотите создать временный домен и загрузить в него.
В нашей системе у нас есть управляемый класс C ++ под названием ModelLoader, который загружает объектные модели, запрашивает информацию об их версии и отбрасывает их - так же, как вы хотите. Этот класс является ключевым элементом нашего управляемого / неуправляемого маршалинга.
Код в ModelLoader должен выполняться во временном домене, потому что мы хотим, чтобы он загружал целевые сборки туда, а затем выгружал домен. Однако основное приложение уже запущено в основном домене, и поэтому оно должно быть в состоянии маршалировать вызовы методов через ModelLoader во временном домене. Поэтому ModelLoader наследует System::MarshalByRefObject
, что позволяет среде выполнения .NET выполнять всю магию маршалинга.
Итак, основные шаги примерно такие:
Загрузить сборку, которая содержит код для ModelLoader. В нашей системе это встроено в наш основной неуправляемый .EXE, поэтому мы просто используем Reflection :: Assembly :: GetExecutingAssembly (), чтобы получить дескриптор к нему. Если ваш эквивалент ModelLoader находится в отдельной сборке, вам придется каким-то образом его загрузить. Но поскольку вам, вероятно, не нужно выгружать эту сборку, вы можете загрузить ее в основной домен.
Создать временный домен.
Создайте экземпляр вашего класса ModelLoader (очевидно, он будет иметь другое имя в вашей системе) во временном домене.
Маршал дескриптор этого нового экземпляра обратно в ваш основной домен.
Используйте маршалированный маркер из основного домена для выполнения кода во временном домене.
Выгрузить временный домен.
Итак, в коде:
AppDomain ^domain = AppDomain::CreateDomain(L"temp domain");
Assembly ^assembly = Assembly::GetExecutingAssembly();
ObjectHandle ^handle = domain->CreateInstanceFrom(
assembly->Location,L"ModeLoader");
Object ^o = handle->Unwrap();
ModelLoader ^loader = dynamic_cast<ModelLoader^>(o);
loader->GetAssemblyVersion(...);
AppDomain::Unload(domain);
Чтобы избавить вас от головокружения, используются следующие пространства имен:
System::AppDomain
System::Reflection::Assembly
System::Runtime::Remoting::ObjectHandle
System::Object
В вашем ModelLoader вы хотите загрузить целевую сборку и запросить информацию о ее версии. По сравнению со всем остальным это просто:
void ModelLoader::GetAssemblyVersion(const wchar_t *filename, AssemblyName ^name)
{
Assembly ^assembly = Assembly::Load(gcnew String(filename));
name = assembly->GetName();
}
(я сделал эту функцию только сейчас, так что она может быть не совсем правильной.)
Еще одна вещь, на которую следует обратить внимание, это разрешение сборки . Вот как загрузчик сборок преобразует имена сборок в файлы DLL. Это довольно большое поле само по себе, поэтому я не буду больше говорить об этом прямо сейчас. (И в любом случае я не эксперт.) Для начала просто убедитесь, что все сборки, которые вы хотите загрузить, находятся в вашем главном каталоге приложения, и я думаю, что вы будете более или менее в порядке. Затем, когда у вас работает базовая загрузка, вы можете беспокоиться о более сложном разрешении.