[英]in linux, mono invoke my .so lib return System.EntryPointNotFoundException
here is my c++ code 这是我的C ++代码
#include "_app_switcher.h"
std::string c_meth(std::string str_arg) {
return "prpr";
}
my mono code: 我的单声道代码:
[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);
the err output: 错误输出:
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
I guess it's because my header file is not in /usr/include, so how to specific c++ header file in mono? 我猜这是因为我的头文件不在/ usr / include中,所以如何在mono中指定c ++头文件?
There are a couple of reasons why your code doesn't work: 您的代码无法正常工作的原因有两个:
c_meth
does not exist within your shared library. c_meth
在共享库中不存在。 The function that does exist is _Z6c_methNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
. _Z6c_methNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
。 std::string
and the .NET class System.String
are different and entirely unrelated. std::string
和.NET类System.String
是不同的,并且完全不相关。 .NET only knows how to marshal System.String
to const char*
and vice versa. System.String
为const char*
,反之亦然。 C++ allows function overloading. C ++允许函数重载。 That means it needs a way to tell
void foo(int)
apart from void foo(std::string)
. 这意味着它需要一种方法来区分
void foo(int)
和void foo(std::string)
。 To do this, it uses name mangling to generate a unique name for each overload. 为此,它使用名称修饰为每个重载生成唯一的名称。 To disable name mangling for a function you declare it with the
extern "C"
specifier. 要禁用功能的名称修饰,请使用
extern "C"
说明符对其进行声明。 This also limits you to C-like interfaces, so you can only pass and return primitive objects and pointers. 这也将您限制为类似C的接口,因此您只能传递和返回原始对象和指针。 No classes or references.
没有类别或参考。 That's fine though, since .NET doesn't know what to do with C++ classes.
不过,这很好,因为.NET不知道如何处理C ++类。 You need to accept a raw
const char*
parameter and return a const char*
: 您需要接受一个原始的
const char*
参数并返回一个const char*
:
extern "C" const char* c_meth(const char* str_arg) {
return "prpr";
}
Returning strings is also problematic. 返回字符串也是有问题的。 .NET will try to de-allocate the returned memory after copying the string to the managed heap.
将字符串复制到托管堆后,.NET将尝试取消分配返回的内存。 Since the string returned in this case wasn't allocated using the appropriate allocation method, that will fail.
由于在这种情况下返回的字符串未使用适当的分配方法进行分配,因此将失败。 To avoid this you'll need to declare the imported method in C# to return an
IntPtr
and use Marshal.PtrToString(Ansi|Unicode)
to convert to a System.String
. 为避免这种情况,您需要在C#中声明导入的方法以返回
IntPtr
并使用Marshal.PtrToString(Ansi|Unicode)
转换为System.String
。
If you do need to return something other than a string constant, you have a couple options: 如果确实需要返回字符串常量以外的其他值,则有两种选择:
System.Text.StringBuilder
: System.Text.StringBuilder
在C#中分配内存,并将缓冲区传递给非托管函数: C++ side: 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# side: 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);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.