在 linux 中,单声道调用我的 .so 库 return System.EntryPointNotFoundException
in linux, mono invoke my .so lib return System.EntryPointNotFoundException
这是我的 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_meth
。确实存在的函数是 _Z6c_methNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
.
- C++ class
std::string
和 .NET class System.String
是不同的并且完全不相关。 .NET 只知道如何将 System.String
编组为 const char*
,反之亦然。
C++ 允许函数重载。这意味着它需要一种方法来区分 void foo(int)
和 void foo(std::string)
。为此,它使用 name mangling 为每个重载生成一个唯一的名称。要禁用函数的名称修改,您可以使用 extern "C"
说明符对其进行声明。这也将您限制为类似 C 的接口,因此您只能传递和 return 原始对象和指针。没有 classes 或引用。不过这很好,因为 .NET 不知道如何处理 C++ classes。您需要接受原始 const char*
参数和 return 一个 const char*
:
extern "C" const char* c_meth(const char* str_arg) {
return "prpr";
}
返回字符串也是有问题的。 .NET 将在将字符串复制到托管堆后尝试取消分配 returned 内存。由于本例中的字符串 returned 未使用适当的分配方法进行分配,因此会失败。为避免这种情况,您需要在 C# 中将导入的方法声明为 return 和 IntPtr
并使用 Marshal.PtrToString(Ansi|Unicode)
转换为 System.String
.
如果你确实需要 return 除了字符串常量之外的东西,你有几个选择:
- 使用适当的函数为字符串分配内存。要使用的功能取决于平台。有关要使用哪个函数的信息,请参阅 Mono's documentation。
- 在 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);
这是我的 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_meth
。确实存在的函数是_Z6c_methNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
. - C++ class
std::string
和 .NET classSystem.String
是不同的并且完全不相关。 .NET 只知道如何将System.String
编组为const char*
,反之亦然。
C++ 允许函数重载。这意味着它需要一种方法来区分 void foo(int)
和 void foo(std::string)
。为此,它使用 name mangling 为每个重载生成一个唯一的名称。要禁用函数的名称修改,您可以使用 extern "C"
说明符对其进行声明。这也将您限制为类似 C 的接口,因此您只能传递和 return 原始对象和指针。没有 classes 或引用。不过这很好,因为 .NET 不知道如何处理 C++ classes。您需要接受原始 const char*
参数和 return 一个 const char*
:
extern "C" const char* c_meth(const char* str_arg) {
return "prpr";
}
返回字符串也是有问题的。 .NET 将在将字符串复制到托管堆后尝试取消分配 returned 内存。由于本例中的字符串 returned 未使用适当的分配方法进行分配,因此会失败。为避免这种情况,您需要在 C# 中将导入的方法声明为 return 和 IntPtr
并使用 Marshal.PtrToString(Ansi|Unicode)
转换为 System.String
.
如果你确实需要 return 除了字符串常量之外的东西,你有几个选择:
- 使用适当的函数为字符串分配内存。要使用的功能取决于平台。有关要使用哪个函数的信息,请参阅 Mono's documentation。
- 在 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);