如何正确地将字符*从非托管DLL返回到C#?
功能签名: char * errMessage(int err); 字符*错误消息(int err); 我的代码: [DllImport("api.dll")] internal static extern char[] errMessage(int err); ... char[] message = errMessage(err); [DllImport(“api.dll”)] 内部静态外部字符[]错误消息(int err); ... char[]message=errMessage(err); 这将返回一个错误: Cannot marshal 'return value': Invalid managed/unmanaged type combination. 无法封送“返回值”:无效的托管/非托管类型组合。 我做错了什么?谢谢您的帮助。试试这个:如何正确地将字符*从非托管DLL返回到C#?,c#,.net,c++,interop,unmanaged,C#,.net,C++,Interop,Unmanaged,功能签名: char * errMessage(int err); 字符*错误消息(int err); 我的代码: [DllImport("api.dll")] internal static extern char[] errMessage(int err); ... char[] message = errMessage(err); [DllImport(“api.dll”)] 内部静态外部字符[]错误消息(int err); ... char[]message=errMess
[DllImport("api.dll")]
[return : MarshalAs(UnmanagedType.LPStr)]
internal static extern string errMessage(int err);
...
string message = errMessage(err);
我相信C#足够聪明,可以处理指针并返回字符串
编辑:添加了MarshalAs属性尝试在托管端使用字符串。您不妨将字符集设置为Ansi,请参见。总之,该函数应该返回一个IntPtr,您必须使用Marshal.PtrToString*将其转换为托管字符串对象。一个简单而健壮的方法是,如果是
StringBuilder
,则在表单中以C#形式分配一个缓冲区,将其传递给非托管代码并在那里填充
例如:
C
#include <string.h>
int foo(char *buf, int n) {
strncpy(buf, "Hello World", n);
return 0;
}
[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());
}
测试:
你好,世界
这是一个可怕的函数签名,无法猜测字符串是如何分配的。也不能释放字符串的内存。如果在声明中将返回类型声明为“string”,那么P/Invoke封送拆收器将调用指针上的CoTaskMemFree()。这不太可能是恰当的。它会在XP中无声地失败,但会在Vista和Win7中使您的程序崩溃
在非托管程序中甚至不能可靠地调用该函数。使用正确版本的free()的可能性很小。您所能做的就是将其声明为IntPtr,并使用marshal.PtrToStringAnsi()自行封送返回值。在Taskmgr.exe中观察时,请确保编写一个测试程序,该程序可以执行一百万次。如果程序的VM大小无限制地增长,则内存泄漏无法堵塞。使用此解决方案释放为字符串分配的空间的最佳做法是什么?这取决于内存的分配方式。如果它是用CoTaskMemAlloc分配的,那么应该使用Marshal.FreeCoTaskMem。否则,不要释放它,因为它肯定是在不属于您的程序集的堆中用new/malloc分配的。字符集可能是Ansi,但希望IronicMuffin知道它是什么。即使使用封送处理as,如果它更改为字符串,它也无法找到入口点。这是我想要的解决方案。我们知道我们能做些什么来让它工作吗?也许试着将原型声明为返回int?这不应该被提升和接受。p/invoke封送拆收器将尝试销毁通过调用
CoTaskMemFree
返回的C字符串。除非通过调用CoTaskMemAlloc
来分配字符串,否则这通常是泄漏或运行时错误,或者两者兼而有之。这很好,但我没有访问非托管源的权限。
Hello World