在C#中编组char **

我正在接受带有char**代码(即指向字符串的指针):

 int DoSomething(Whatever* handle, char** error); 

基本上,它需要处理其状态,如果出现问题,它会返回错误代码和可选的错误消息(内存分配在外部,并使用第二个函数释放。这部分我已经指出:))。

但是,我不确定如何处理C#。 我目前所拥有的:

 [DllImport("mydll.dll", CallingConvention = CallingConvention.Cdecl)] private static unsafe extern int DoSomething(IntPtr handle, byte** error); public static unsafe int DoSomething(IntPtr handle, out string error) { byte* buff; int ret = DoSomething(handle, &buff); if(buff != 0) { // ??? } else { error = ""; } return ret; } 

我已经四处寻找,但我无法弄清楚如何将其变成一个byte[] ,适合提供给UTF8Encoding.UTF8.GetString()

我是在正确的轨道上吗?

编辑:为了更明确,库函数分配内存 ,必须通过调用另一个库函数释放。 如果一个解决方案没有给我一个指针,我可以释放,解决方案是不可接受的。

奖金问题:如上所述,此库使用UTF-8作为其字符串。 我需要在P / Invokes中做一些特殊的事情,还是只使用string作为普通的const char*参数?

您应该只能使用ref string并让运行时默认marshaller为您处理此转换。 您可以使用[MarshalAs(UnmanagedType.LPStr)]提示参数的字符宽度,以确保使用的是8位字符。

由于你有一个特殊的释放方法来调用,你需要保留指针,就像你已经在你的问题的例子中所示。

这是我写的方式:

 [DllImport("mydll.dll", CallingConvention = CallingConvention.Cdecl)] private static unsafe extern int DoSomething( MySafeHandle handle, void** error); // byte** should work, too, I'm just lazy 

然后你可以得到一个字符串:

 var errorMsg = Marshal.PtrToStringAnsi(new IntPtr(*error)); 

并清理:

 [DllImport("mydll.dll", CallingConvention = CallingConvention.Cdecl)] private static extern int FreeMyMemory(IntPtr h); // ... FreeMyMemory(new IntPtr(error)); 

现在我们有编组错误,所以只需返回它。

 return errorMsg; 

还要注意MySafeHandle类型,它将inheritance自System.Runtime.InteropServices.SafeHandle 。 虽然不是严格需要(您可以使用IntPtr),但在使用本机代码时,它可以为您提供更好的句柄管理。 在这里阅读: http : //msdn.microsoft.com/en-us/library/system.runtime.interopservices.safehandle.aspx 。

作为参考,这里的代码编译( 但是,尚未测试,正在进行下一次测试,100%工作),它可以满足我的需要。 如果有人能做得更好,那就是我所追求的:D

 public static unsafe int DoSomething(IntPtr handle, out string error) { byte* buff; int ret = DoSomething(handle, &buff); if(buff != null) { int i = 0; //count the number of bytes in the error message while (buff[++i] != 0) ; //allocate a managed array to store the data byte[] tmp = new byte[i]; //(Marshal only works with IntPtrs) IntPtr errPtr = new IntPtr(buff); //copy the unmanaged array over Marshal.Copy(buff, tmp, 0, i); //get the string from the managed array error = UTF8Encoding.UTF8.GetString(buff); //free the unmanaged array //omitted, since it's not important //take a shot of whiskey } else { error = ""; } return ret; } 

编辑:修复了while循环中的逻辑,它有一个错误。