在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
循环中的逻辑,它有一个错误。