从C ++ / CLI加载相互依赖的程序集 [英] Loading interdependent assemblies from C++/CLI
问题描述
我想从C ++ / CLI加载两个程序集;程序集A依赖程序集B,都是VB.Net项目(3.5)。我希望他们从一个字节数组加载,所以我使用Assembly :: Load(),但是当我试图从程序集A实例化一个类,框架忽略以前加载的程序集B,并尝试重新加载它,失败,因为它不在搜索路径中。程序集的名称是相同的,所以我不知道为什么它失败。为了测试的目的,我的程序直接从编译的映像加载字节,但实际代码将加载不同。这是我的测试代码:
#includestdafx.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&
FileStream ^ f;
f = gcnew FileStream(Lc:\\ ... \\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(Lc:\\ ... \\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;
//这里我得到文件未找到异常!
Object ^ mf = assemblya-> CreateInstance(LAssemblyA.MainForm);
//除非我将assemblyb.dll复制到应用程序的文件夹中,否则没有到达这一行:
mf-> GetType() - > InvokeMember(LShowDialog,BindingFlags ::默认| BindingFlags :: InvokeMethod,
mf-> GetType() - > DefaultBinder,mf,nullptr);
return 0;
}
错误是:
无法加载文件或程序集 AssemblyB,Version = 1.0.3650.39903,Culture = neutral,PublicKeyToken = null 或其中一个依赖项。系统找不到指定的文件。
当我检查assemblyb-> FullName时,它会正确地显示 AssemblyB,Version = 1.0.3650.39903,文件=中立,PublicKeyToken = null '。
当然,如果我将AssemblyB.dll复制到我的测试程序的文件夹,代码工作正常,
(顺便说一下,我的第二个步骤将尝试让AssemblyA使用我的C ++ / CLI exe将公开的类。)
好吧,我只是尴尬自己。
//这个类只是用于为assemblyB持有一个管理的静态变量
ref class解析器{
public:
static Assembly ^ assemblyB;
};
//这是解析程序集的委托
Assembly ^ ResolveHandler(Object ^ Sender,ResolveEventArgs ^ args)
{
//警告: args为程序集名称!
return Resolver :: assemblyB;
}
。
。
。
[STAThreadAttribute]
int main(array< System :: String ^> ^ args)
{
//设置AssemblyResolve事件的处理程序
AppDomain :: CurrentDomain-> AssemblyResolve + = gcnew ResolveEventHandler(ResolveHandler);
。
。
。
//将assemblyb加载到可用于解析器委托的静态变量
Resolver :: assemblyb = Assembly :: Load(bytes);
。
。
。
我希望有人发现这很有用。 :)
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.)
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. :)
这篇关于从C ++ / CLI加载相互依赖的程序集的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!