在linux中,mono调用我的.so-lib返回System.EntryPointNotFoundException

in linux, mono invoke my .so lib return System.EntryPointNotFoundException

本文关键字:so-lib 返回 System EntryPointNotFoundException 我的 调用 linux mono      更新时间:2023-10-16

这是我的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++头文件呢?

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

  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)。为此,它使用名称篡改为每个重载生成一个唯一的名称。若要禁用函数的名称篡改,请使用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的文档
  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);