从C ++ / CLI加载相互依赖的程序集 [英] Loading interdependent assemblies from C++/CLI

查看:249
本文介绍了从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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆