Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何正确地将字符*从非托管DLL返回到C#?_C#_.net_C++_Interop_Unmanaged - Fatal编程技术网

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

如何正确地将字符*从非托管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

功能签名:

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. 无法封送“返回值”:无效的托管/非托管类型组合。 我做错了什么?谢谢您的帮助。

试试这个:

[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