如何正确地将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