【问题标题】:in linux, mono invoke my .so lib return System.EntryPointNotFoundException在 linux 中,单声道调用我的 .so lib 返回 System.EntryPointNotFoundException
【发布时间】:2018-07-17 14:33:28
【问题描述】:

这是我的 C++ 代码

#include "_app_switcher.h"

std::string c_meth(std::string str_arg) {
    return "prpr";
}

我的单声道代码:

    [Test]
    public void TestDraft()
    {
        Console.WriteLine(c_meth("prpr"));
    }

    [DllImport("/home/roroco/Dropbox/cs/App.Switcher/c/app-switcher/lib/libapp-switcher-t.so")]
    private static extern string c_meth(string strArg);

错误输出:

System.EntryPointNotFoundException : c_meth
  at (wrapper managed-to-native) Test.Ro.EnvTest.c_meth(string)
  at Test.Ro.EnvTest.TestDraft () [0x00001] in /home/roroco/Dropbox/cs/Ro/TestRo/EnvTest.cs:15 
  at (wrapper managed-to-native) System.Reflection.MonoMethod.InternalInvoke(System.Reflection.MonoMethod,object,object[],System.Exception&)
  at System.Reflection.MonoMethod.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00032] in <71d8ad678db34313b7f718a414dfcb25>:0

我猜是因为我的头文件不在/usr/include中,那么如何在mono中指定c++头文件?

【问题讨论】:

  • C++ 的 std::string 和 .NET 的 System.String 不是同一类型。即使您修复了您现在看到的即时错误,这也不起作用。

标签: c# c++ mono


【解决方案1】:

您的代码不起作用的原因有几个:

  1. 您的共享库中不存在函数c_meth。确实存在的函数是_Z6c_methNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
  2. C++ 类std::string 和.NET 类System.String 是不同的并且完全不相关。 .NET 只知道如何将System.String 编组为const char*,反之亦然。

C++ 允许函数重载。这意味着它需要一种方法来区分void foo(int)void foo(std::string)。为此,它使用name mangling 为每个重载生成一个唯一名称。要禁用函数的名称修改,请使用 extern "C" 说明符声明它。这也限制了您使用类似 C 的接口,因此您只能传递和返回原始对象和指针。没有类或引用。不过这很好,因为 .NET 不知道如何处理 C++ 类。你需要接受一个原始的const char* 参数并返回一个const char*

extern "C" const char* c_meth(const char* str_arg) {
    return "prpr";
}

返回字符串也是有问题的。 .NET 将在将字符串复制到托管堆后尝试取消分配返回的内存。由于在这种情况下返回的字符串不是使用适当的分配方法分配的,因此将失败。为避免这种情况,您需要在 C# 中声明导入的方法以返回 IntPtr 并使用 Marshal.PtrToString(Ansi|Unicode) 转换为 System.String

如果您确实需要返回字符串常量以外的内容,您有几个选择:

  1. 使用适当的函数为字符串分配内存。要使用的功能取决于平台。请参阅 Mono's documentation 了解有关使用哪个功能的信息。
  2. 在 C# 中分配内存并使用 System.Text.StringBuilder 将缓冲区传递给非托管函数:

C++ 方面:

extern "C" void c_meth(const char* str_arg, char* outbuf, int outsize) {
    std::string ret = someFunctionThatReturnsAString(str_arg);
    std::strncpy(outbuf, ret.c_str(), outsize);
}

C#端:

[Test]
public void TestDraft()
{
    StringBuilder sb = new StringBuilder(256)
    c_meth("prpr", sb, 256);
    Console.WriteLine(sb.ToString());
}

[DllImport("/home/roroco/Dropbox/cs/App.Switcher/c/app-switcher/lib/libapp-switcher-t.so")]
private static extern void c_meth(string strArg, StringBuilder outbuf, int outsize);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-20
    • 2013-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多