问题
I want to load two assemblies from C++/CLI; assembly A depends on assembly B, and both are VB.Net projects (3.5). I want them to load from a byte array, so I use Assembly::Load(), but when I try to instantiate a class from assembly A, the framework ignores the previously loaded assembly B and attempts to load it again, which fails because it is not in the search path. The "Name" of the assembly is the same, so I don't know why it fails. For testing purposes, my program loads the bytes directly from the compiled image, but the real code will be loaded differently. This is my test code:
#include "stdafx.h"
using namespace System;
using namespace System::Windows::Forms;
using namespace System::IO;
using namespace System::Reflection;
[STAThreadAttribute]
int main(array<System::String ^> ^args)
{
array<unsigned char>^ bytes;
FileStream^ f;
f = gcnew FileStream(L"c:\\...\\AssemblyB.dll", FileMode::Open);
bytes = gcnew array<unsigned char>((int)f->Length);
f->Read( bytes, 0, (int) f->Length );
f->Close();
f = nullptr;
Assembly^ assemblyb = Assembly::Load(bytes);
f = gcnew FileStream(L"c:\\...\\AssemblyA.dll", FileMode::Open);
bytes = gcnew array<unsigned char>((int)f->Length);
f->Read( bytes, 0, (int) f->Length );
f->Close();
f = nullptr;
Assembly^ assemblya = Assembly::Load(bytes);
bytes = nullptr;
// Here I get the file not found exception!
Object^ mf = assemblya->CreateInstance(L"AssemblyA.MainForm");
// This line is not reached unless I copy assemblyb.dll to my app's folder:
mf->GetType()->InvokeMember(L"ShowDialog",BindingFlags::Default | BindingFlags::InvokeMethod,
mf->GetType()->DefaultBinder, mf, nullptr );
return 0;
}
The error is:
Could not load file or assembly 'AssemblyB, Version=1.0.3650.39903, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
When I check assemblyb->FullName, it says exactly 'AssemblyB, Version=1.0.3650.39903, Culture=neutral, PublicKeyToken=null'.
Of course, if I copy AssemblyB.dll to my test program's folder the code works just fine, but that's not what I want.
Any ideas?
(By the way, my second step will be attempt to make AssemblyA use classes that my C++/CLI exe will expose.)
回答1:
OK, I just embarrased myself. It's all in the docs.
// This class is just for holding a managed static variable for assemblyB
ref class Resolver {
public:
static Assembly^ assemblyB;
};
// This is the delegate for resolving assemblies
Assembly^ ResolveHandler(Object^ Sender, ResolveEventArgs^ args)
{
// Warning: this should check the args for the assembly name!
return Resolver::assemblyB;
}
.
.
.
[STAThreadAttribute]
int main(array<System::String ^> ^args)
{
// Set up the handler for the AssemblyResolve event
AppDomain::CurrentDomain->AssemblyResolve += gcnew ResolveEventHandler( ResolveHandler );
.
.
.
// Load assemblyb into the static variable available to the resolver delegate
Resolver::assemblyb = Assembly::Load(bytes);
.
.
.
I hope someone finds this useful. :)
来源:https://stackoverflow.com/questions/1978046/loading-interdependent-assemblies-from-c-cli