c# - C# 字节数组中的 RAWINPUT RAWHID 结构

标签 c# arrays byte structure raw-input

我正在尝试使用以下方法从 HID 设备读取数据:

uint dwsize = 0;
//RAWINPUT input = new RAWINPUT();
uint result = GetRawInputData(lParam, RID_INPUT, IntPtr.Zero, ref dwsize, Marshal.SizeOf(typeof(RAWINPUTHEADER)));

//_rawBuffer = new RAWINPUT(new RAWINPUTHEADER(), new RAWDATA(new RAWKEYBOARD(), new RAWHID(0,0)));
result = GetRawInputData(lParam, RID_INPUT, out _rawBuffer, ref dwsize, Marshal.SizeOf(typeof(RAWINPUTHEADER)));

此代码有效,但从 RAWHID 结构中获取字节数组存在一个问题,根据 MSDN 文档,它应该是这样的:

typedef struct tagRAWHID {
  DWORD dwSizeHid;
  DWORD dwCount;
  BYTE  bRawData[1];
} RAWHID, *PRAWHID, *LPRAWHID;

这是我的:

[StructLayout(LayoutKind.Sequential)]
internal struct RAWHID
{
  public uint dwSizHid;
  public uint dwCount;
  public byte bRawData;
}

我试图到处寻找,但找不到有效的解决方案。 我还尝试使用此代码获取 IntPtr 而不是字节数组并编码复制它:

int length = (int)(_rawBuffer.data.hid.dwCount * _rawBuffer.data.hid.dwSizHid);
byte[] bytes = new byte[length];
GCHandle pinnedPacket = GCHandle.Alloc(_rawBuffer.data.hid.bRawData, GCHandleType.Pinned);
Marshal.Copy(_rawBuffer.data.hid.bRawData, bytes, 0, length);
pinnedPacket.Free();

我固定它的原因是因为我不断收到

System.AccessViolationException: 'Attempted to read or write protected memory. This is often an indication that other memory is corrupt.'

错误。

问题简短:如何使 RAWHID 结构与 C# 中的字节数组一起使用

最佳答案

我也不确定如何在结构中定义动态大小的字节数组 BYTE bRawData[1],所以我最终从原始 IntPtr 中获取它。我刚刚从 RAWHID 定义中删除了它:

[StructLayout(LayoutKind.Sequential)]
public struct RAWHID
{
    public int Size;
    public int Count;
}

[StructLayout(LayoutKind.Sequential)]
public struct RawInput
{
    /// <summary>
    /// Header for the data.
    /// </summary>
    public RawInputHeader Header;
    public Union Data;

    [StructLayout(LayoutKind.Explicit)]
    public struct Union
    {
        [FieldOffset(0)] public RAWMOUSE Mouse;
        [FieldOffset(0)] public RAWKEYBOARD Keyboard;
        [FieldOffset(0)] public RAWHID HID;
    }
}

下面是我实际读取数据并将其写入控制台的方式:

private static void ProcessInputMessage(Message message)
{
    var headerSize = (uint) Marshal.SizeOf<RawInputHeader>();
    uint rawInputSize = 0;
    var result = GetRawInputData(message.LParam, RID_INPUT, IntPtr.Zero, ref rawInputSize, headerSize);
    if (result != 0)
    {
        Console.WriteLine($"Failed to get message size: {result}");
        return;
    }

    using var rawInputPointer = new AllocHGlobalWrapper(rawInputSize);
    if (!rawInputPointer.Success)
    {
        return;
    }

    result = GetRawInputData(message.LParam, RID_INPUT, rawInputPointer.Value, ref rawInputSize, headerSize);
    if (result != rawInputSize)
    {
        Console.WriteLine($"Failed to get raw data: {result}");
        return;
    }
    
    var input = Marshal.PtrToStructure<RawInput>(rawInputPointer.Value);
    var buffer = new IntPtr(rawInputPointer.Value.ToInt64() + headerSize + Marshal.SizeOf<RAWHID>());

    if (input.Header.Type == RawInputType.HID)
    {
        for(var i  = 0; i < input.Data.HID.Count; i++)
        {
            var data = new byte[input.Data.HID.Size];
            Marshal.Copy(buffer, data, i * input.Data.HID.Size, input.Data.HID.Size);
            Console.WriteLine(BitConverter.ToString(data));
        }
    }
}

请注意,AllocHGlobalWrapper 只是我编写的一个简单助手,用于将对 Marshal.AllocHGlobal(...) 的调用包装在调用 Marshal.FreeHGlobal( ...) 当它被处理时,所以 rawInputPointer.Value 只是返回指向分配给 RawInput 的内存的 IntPtr .

关于c# - C# 字节数组中的 RAWINPUT RAWHID 结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48776221/

相关文章:

c# - ServiceStack 默认格式

c# - 如何判断 PropertyInfo 是否属于特定枚举类型?

java - 在 Java 中将十六进制字符串转换为字节

java - 了解 java 中的有符号数和补码

在c语言中可以创建一个只有一位的变量吗?

c# - 如何从 Windows Phone 7 中的 m3u8 文件流式传输视频文件

c# - 什么对象类型用于 Sitefinity 中的单个相关图像属性?

c - 我的 int isMember() 上的循环函数

Java 用户输入未结束

java - 如何在Java中将分割后的字符串存储为数组?