如何正确地将char *从非托管DLL返回到C#?

function签名:

 char * errMessage(int err);

我的代码:

 [的DllImport( “api.dll”)]       
 internal static extern char [] errMessage(int err);
 ...
 char [] message = errMessage(err);

这会返回一个错误:

无法封送“返回值”:无效的托管/非托管类型组合。

我究竟做错了什么? 谢谢你的帮助。

试试这个:

[DllImport("api.dll")] [return : MarshalAs(UnmanagedType.LPStr)] internal static extern string errMessage(int err); ... string message = errMessage(err); 

我相信C#足够智能来处理指针并返回一个字符串。

编辑:添加了MarshalAs属性

一种简单而健壮的方法是在StringBuilder以C#forms分配缓冲区,将其传递给非托管代码并将其填充到那里。

例:

C

 #include  int foo(char *buf, int n) { strncpy(buf, "Hello World", n); return 0; } 

C#

 [DllImport("libfoo", EntryPoint = "foo")] static extern int Foo(StringBuilder buffer, int capacity); static void Main() { StringBuilder sb = new StringBuilder(100); Foo(sb, sb.Capacity); Console.WriteLine(sb.ToString()); } 

测试:

你好,世界

看到这个问题 。 总而言之,该函数应返回一个IntPtr,您必须使用Marshal.PtrToString *将其转换为托管String对象。

这是一个可怕的函数签名,没有办法猜测字符串是如何分配的。 你也不能为字符串释放内存。 如果在声明中将返回类型声明为“string”,则P / Invoke编组器将在指针上调用CoTaskMemFree()。 这不太合适。 它会在XP中默默地失败,但会在Vista和Win7中崩溃你的程序。

您甚至无法在非托管程序中可靠地调用该函数。 你使用正确版本的free()的几率非常小。 您所能做的就是将其声明为IntPtr并使用Marshal.PtrToStringAnsi()自行编组返回值。 当你在Taskmgr.exe中观察它时,一定要编写一个测试程序,这样做了一百万次。 如果程序的VM大小无限制地增长,则会出现无法插入的内存泄漏。

尝试在托管端使用String。 你也可以将CharSet设置为Ansi