问题描述
我正在尝试在C#中封送hid_device_info结构,但是我不知道如何将wchar_t *字符串转换为托管C#字符串。我已经尝试了MarshalAs属性中的所有可能值,但所有这些值仅返回第一个字符,而没有其他返回值。
我尝试用指针替换所有宽字符串,以便可以手动查看它们,这是到目前为止的结构:
public struct HidDeviceInfo
{
public IntPtr path; // This one marshals fine because it's just a regular char_t*
public ushort vendor_id;
public ushort product_id;
public IntPtr serial_number; // wchar_t*
public ushort release_number;
public IntPtr manufacturer_string; // wchar_t*
public IntPtr product_string; // wchar_t*
public ushort usage_page;
public ushort usage;
public int interface_number;
public IntPtr next;
}
当我手动遍历指针之一(例如serial_number
)时,我看到所有字符都有4个字节(1个ascii字节,后跟3个零)。我已经尝试了所有可能的Marshal.PtrToString...
方法,但是它们都无法检索完整的字符串。
我怀疑字符串被视为2个字节的字符,因为我无法在C#中的任何地方指定字符宽度,这就是为什么它在第一个字符之后停止的原因。当然,通过了解这一点,我可以轻松编写自己的字符串封送处理程序,但是我觉得必须有一个现有的解决方案,而我却忽略了一些显而易见的事情。
此结构来自P / Invoked函数和Marshal.PtrToStructure
:
[DllImport(LibUsbName,CharSet = CharSet.Unicode)]
public static extern IntPtr hid_enumerate(ushort vendorId,ushort productId);
我还尝试了所有可能的CharSet值。
这不能像this question中那样是字符类型不匹配,因为我已经尝试了不同字符类型的所有可能组合。
解决方法
我最终写出了一种对我来说很好用的方法,但前提是所有字符均为ASCII并且字符宽度保证为4个字节。
private static string ToUcs4String(this IntPtr ptr)
{
var builder = new StringBuilder();
var buffer = new byte[4];
while (true)
{
Marshal.Copy(ptr,buffer,4);
if (buffer[0] == 0)
break;
builder.Append((char) buffer[0]);
ptr += 4;
}
return builder.ToString();
}