功能签名:
char * errMessage(int err);
我的代码:
[DllImport("api.dll")] internal static extern char[] errMessage(int err); ... char[] message = errMessage(err);
这会返回错误:
Cannot marshal 'return value': Invalid managed/unmanaged type combination.
我做错了什么?谢谢你的帮助。
答案 0 :(得分:7)
一种简单而强大的方法是在表单中使用StringBuilder
在C#中分配缓冲区,将其传递给非托管代码并将其填充到那里。
示例:
<强> C 强>
#include <string.h>
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());
}
测试:
Hello World
答案 1 :(得分:5)
见this question。总而言之,该函数应返回一个IntPtr,您必须使用Marshal.PtrToString *将其转换为托管String对象。
答案 2 :(得分:5)
这是一个可怕的函数签名,没有办法猜测字符串是如何分配的。你也不能为字符串释放内存。如果在声明中将返回类型声明为“string”,那么P / Invoke编组器将在指针上调用CoTaskMemFree()。这不太合适。它会在XP中无声地失败,但会在Vista和Win7中崩溃你的程序。
您甚至无法在非托管程序中可靠地调用该函数。你使用正确版本的free()的几率非常小。您所能做的就是将其声明为IntPtr并使用Marshal.PtrToStringAnsi()自行编组返回值。当你在Taskmgr.exe中观察它时,一定要编写一个测试程序,这样做了一百万次。如果程序的VM大小无限制地增长,则会出现无法插入的内存泄漏。
答案 3 :(得分:2)
试试这个:
[DllImport("api.dll")]
[return : MarshalAs(UnmanagedType.LPStr)]
internal static extern string errMessage(int err);
...
string message = errMessage(err);
我相信C#足够智能来处理指针并返回一个字符串。
编辑:添加了MarshalAs属性
答案 4 :(得分:0)
尝试在托管端使用String。你也可以将CharSet设置为Ansi