为什么我不能在C#中正确封送UCS-4字符串?

时间:2020-10-03 17:33:55

标签: c# string marshalling widechar

我正在尝试在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中那样是字符类型不匹配,因为我已经尝试了不同字符类型的所有可能组合。

1 个答案:

答案 0 :(得分:1)

我最终写出了一种对我来说很好用的方法,但前提是所有字符均为ASCII并且字符宽度保证为4个字节。

private static string ToUcs4String(this IntPtr ptr)
{
    var builder = new StringBuilder();
    var buffer = new byte[4];
    while (true)
    {
        Marshal.Copy(ptr, buffer, 0, 4);
        if (buffer[0] == 0)
            break;
        builder.Append((char) buffer[0]);
        ptr += 4;
    }

    return builder.ToString();
}