我正在尝试使用以下方法从 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/