使用 C++ 和嵌入式单声道调用 C# DLL 时无法加载程序集系统

Posted

技术标签:

【中文标题】使用 C++ 和嵌入式单声道调用 C# DLL 时无法加载程序集系统【英文标题】:Could not load assembly System when using C++ and embedded mono to call to C# DLL 【发布时间】:2017-09-26 19:28:16 【问题描述】:

我有一个 C# 示例代码,它在 Linux 上使用 xbuild 编译成 DLL,例如:

using System;
using System.IO;
using System.Collections.Generic;
// ...

namespace MySamples

public class MyExample

    public static void test()
    
        SortedSet<int> ss = new SortedSet<int>();
     
    // main function calls for test()


我可以在命令行中使用xbuild MyExample.csproj 轻松地将示例代码编译为exedll,然后使用mono MyExample.exe 运行——一切正常,示例代码返回预期结果。

现在我想从我的 C++ 代码中调用示例代码,特别是调用 test() 函数。我为此使用单声道运行时,这是我的 C++ 代码:

#include <mono/jit/jit.h>
#include <mono/metadata/object.h>
#include <mono/metadata/environment.h>
#include <mono/metadata/assembly.h>
#include <mono/metadata/debug-helpers.h>
#include <mono/metadata/mono-config.h>

// ...
MonoDomain* domain = mono_jit_init("MyExample.dll");
MonoAssembly* assembly = mono_domain_assembly_open(domain, "MyExample.dll");
mono_config_parse("MyExample.dll.config");

// mono is not installed in default locations:
mono_set_dirs("mypath/lib/mono", "mypath/etc/mono");

MonoImage* image = mono_assembly_get_image(assembly);

MonoClass* klass = mono_class_from_name(image, "MySamples", "MyExample");
MonoObject* object = mono_object_new(domain, klass);
mono_runtime_object_init(object);

// call test()
MonoMethodDesc* mdesc = mono_method_desc_new(":test()", false);
MonoMethod* method = mono_method_desc_search_in_class(mdesc, klass);
mono_runtime_invoke(method, object, NULL, NULL);

// shutdown the runtime
mono_jit_cleanup (domain);

C++ 代码在运行时返回错误类型:

未处理的异常: System.IO.FileNotFoundException:无法加载文件或程序集“系统,版本 = 4.0.0.0,文化 = 中性,PublicKeyToken = ...”或其依赖项之一。 ...

因为我知道如果我通过命令行使用mono 运行相同的代码并且它可以工作,我觉得我的 C++ 代码以及我如何设置单声道运行时存在问题。我通过添加 mono_set_dirs 修复了一堆其他错误,因为我的 Mono 没有安装到默认目录中(它是从源代码构建的)。

我在 Ubuntu 16.04 上,如果重要的话,mono 是从源代码构建的,CMake 用于编译我的 C++ 代码,MyExample.dll.config 内容:

<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
    </startup>    
</configuration>

*.csproj 文件以下列方式包含System

<Reference Include="System" />

再一次,当我从命令行(不是来自 C++ 项目)使用 mono 并使用现在的 C# 设置时,我能够运行 test()

还有一件奇怪的事情:如果我将SortedSet&lt;int&gt; 替换为List&lt;int&gt;,它运行时不会抛出任何错误。怎么可能? -they belong to the same namespace。我检查了其他类型,在初始化它们中的大多数时,都会抛出异常。

有什么想法吗?我一直在检查mono embedded docs 试图找出我的设置可能有什么问题,但这是我所能达到的。我是 C#、单声道运行时和嵌入式单声道的初学者。

【问题讨论】:

可能相关:***.com/questions/8873091/… - 你检查过你的单声道编译器标志了吗?特别是-sdk=4 @JoshE 我使用xbuild,它使用csc。但我可以看到它链接到mscorlib.dll 作为参考。正如我在问题中所说,我觉得问题出在 C++ 代码上,而不是 C#。 我明白 - 我是 b/c System.Collections.Generic 的原因是可能缺少的参考;错误消息“覆盖”了这一点,顺便提到了or one of its' dependencies。你的 csproj 没有引用 System.Collections.Generic,我也注意到了。它可能在 CLI 中工作,因为幸运/DLL 恰好可用于 proc @JoshE 据我了解,System.Collections.GenericSystem.dll 中的命名空间,因此我不必将其包含在csproj 中。告诉我,如果我绞尽脑汁。当我查看不同版本(4.0、4.5、4.6.1、...)的单声道 DLL 时,我也看不到 System.Collections.Generic.dll。这意味着它实际上找不到非常确定的版本的System.dll 您正在寻找System.Collections.DLL,其中包含System.Collections.Generic。你看到那个 DLL 了吗? 【参考方案1】:

问题是如此的微不足道——我在我的 C++ 代码中弄乱了 mono lib 路径。显然,您需要提供前缀,而不是完整路径。所以,就我而言,我不得不使用:

mono_set_dirs("mypath/lib", "mypath/etc");

最后不使用mono

【讨论】:

以上是关于使用 C++ 和嵌入式单声道调用 C# DLL 时无法加载程序集系统的主要内容,如果未能解决你的问题,请参考以下文章

如何使用嵌入在 C++ 中的单声道编译 C# 代码?

单声道嵌入,从 C 调用 C# 泛型方法

使用 C#“输出参数”嵌入单声道

调试从 C++ 调用的 C# dll(嵌入 Mono)

通过单声道将数组从 C++ 传递给 C#

单声道嵌入,在不知道命名空间的情况下获取 MonoClass*