Need help using Raw Input under C#

J

Jason

I have an application that uses an attached GPS through the COM port.
Unfortunately it seems that time has moved on and more and more GPS devices
are native "HID" devices connected to a USB port. (Good news for Vista 64bit
users I guess!) Unfortunately as far as I can tell I need to use Raw Input
from User32.dll in order to find the GPS device and register my application
to receive data from it. The problem I am having is I don't know how to
setup my RAWINPUTDEVICE structure for the GPS so I can register it. I
thought I would try to use GetRawInputDeviceList to get a list of all the
RawInput devices (Successful, good examples online) and then take each
device in the list and call GetRawDeviceInfo with the RIDI_DEVICEINFO flag
in order to get the RID_DEVICE_INFO struct populated with the detailed
information I need in order to create a proper RAWINPUTDEVICE. Unfortunately
this is where I am failing. The RID_DEVICE_INFO structure uses a C/C++ union
in it and I have no idea how to set this up in C# properly. Here is some
code:

The examples I saw suggested setting up the structs like so:
[StructLayout(LayoutKind.Sequential)]
internal struct RID_DEVICE_INFO_HID
{
[MarshalAs(UnmanagedType.U4)]
public int dwVendorId;
[MarshalAs(UnmanagedType.U4)]
public int dwProductId;
[MarshalAs(UnmanagedType.U4)]
public int dwVersionNumber;
[MarshalAs(UnmanagedType.U2)]
public ushort usUsagePage;
[MarshalAs(UnmanagedType.U2)]
public ushort usUsage;
}

Not sure how to approach this with the RID_DEVICE_INFO though. I tried:
[StructLayout(LayoutKind.Sequential)]
internal struct RID_DEVICE_INFO
{
[MarshalAs(UnmanagedType.U4)]
public int cbSize;
[MarshalAs(UnmanagedType.U4)]
public int dwType;

[MarshalAs(UnmanagedType.Struct)]
public RID_DEVICE_INFO_MOUSE mouse;
[MarshalAs(UnmanagedType.Struct)]
public RID_DEVICE_INFO_KEYBOARD keyboard;
[MarshalAs(UnmanagedType.Struct)]
public RID_DEVICE_INFO_HID hid;
}

I also tried an explicit definition with Offsets since I think this is the
proper way to emulate a union in C#

[StructLayout(LayoutKind.Explicit)]
internal struct RID_DEVICE_INFO
{
[System.Runtime.InteropServices.FieldOffset(0)]
public int cbSize;
[System.Runtime.InteropServices.FieldOffset(0)]
public int dwType;

[System.Runtime.InteropServices.FieldOffset(8)]
public RID_DEVICE_INFO_MOUSE mouse;
[System.Runtime.InteropServices.FieldOffset(8)]
public RID_DEVICE_INFO_KEYBOARD keyboard;
[System.Runtime.InteropServices.FieldOffset(8)]
public RID_DEVICE_INFO_HID hid;
}


Then basically I call the GetRawInputDeviceInfo and try to create a
RID_DEVICE_INFO from the resulting pointer. I think this is what is going
wrong:

GetRawInputDeviceInfo(rid.hDevice, RIDI_DEVICEINFO, IntPtr.Zero, ref
pcbSize);
if (pcbSize > 0)
{
//Try getting Device Info
RID_DEVICE_INFO ridi = new RID_DEVICE_INFO();
ridi.cbSize = pcbSize;
IntPtr pData = Marshal.AllocHGlobal((int)pcbSize);
GetRawInputDeviceInfo(rid.hDevice, RIDI_DEVICEINFO,
pData, ref pcbSize);
ridi = (RID_DEVICE_INFO)Marshal.PtrToStructure(pData,
typeof(RID_DEVICE_INFO)); ///Problematic line
Marshal.FreeHGlobal(pData);

if (ridi.dwType == RIM_TYPEHID)
{
System.Diagnostics.Debug.WriteLine("UsagePage: " +
ridi.hid.usUsagePage);
System.Diagnostics.Debug.WriteLine("Usage: " +
ridi.hid.usUsage);
}
}

Marshalling the Pointer to the info data into the info structure just seems
to return junk. It's the same junk each time, but junk. For example the
dwType in the ridi should match the one in the rid and be 0,1, or 2. But the
ridi.dwType often is some large number. It seems as if I can't marshal the
pointer properly or the struct that I'm using is messed up in someway and is
unable to accept the marshalled data. I don't know which side I've gotten
wrong.

Anyone have any helpful pointers for me? Also if you think this topic
belongs in a different newsgroup left me know.

Thanks,

Jason
 
W

Willy Denoyette [MVP]

Jason said:
I have an application that uses an attached GPS through the COM port.
Unfortunately it seems that time has moved on and more and more GPS devices
are native "HID" devices connected to a USB port. (Good news for Vista
64bit users I guess!) Unfortunately as far as I can tell I need to use Raw
Input from User32.dll in order to find the GPS device and register my
application to receive data from it. The problem I am having is I don't
know how to setup my RAWINPUTDEVICE structure for the GPS so I can register
it. I thought I would try to use GetRawInputDeviceList to get a list of all
the RawInput devices (Successful, good examples online) and then take each
device in the list and call GetRawDeviceInfo with the RIDI_DEVICEINFO flag
in order to get the RID_DEVICE_INFO struct populated with the detailed
information I need in order to create a proper RAWINPUTDEVICE.
Unfortunately this is where I am failing. The RID_DEVICE_INFO structure
uses a C/C++ union in it and I have no idea how to set this up in C#
properly. Here is some code:

The examples I saw suggested setting up the structs like so:
[StructLayout(LayoutKind.Sequential)]
internal struct RID_DEVICE_INFO_HID
{
[MarshalAs(UnmanagedType.U4)]
public int dwVendorId;
[MarshalAs(UnmanagedType.U4)]
public int dwProductId;
[MarshalAs(UnmanagedType.U4)]
public int dwVersionNumber;
[MarshalAs(UnmanagedType.U2)]
public ushort usUsagePage;
[MarshalAs(UnmanagedType.U2)]
public ushort usUsage;
}

Not sure how to approach this with the RID_DEVICE_INFO though. I tried:
[StructLayout(LayoutKind.Sequential)]
internal struct RID_DEVICE_INFO
{
[MarshalAs(UnmanagedType.U4)]
public int cbSize;
[MarshalAs(UnmanagedType.U4)]
public int dwType;

[MarshalAs(UnmanagedType.Struct)]
public RID_DEVICE_INFO_MOUSE mouse;
[MarshalAs(UnmanagedType.Struct)]
public RID_DEVICE_INFO_KEYBOARD keyboard;
[MarshalAs(UnmanagedType.Struct)]
public RID_DEVICE_INFO_HID hid;
}

I also tried an explicit definition with Offsets since I think this is the
proper way to emulate a union in C#

[StructLayout(LayoutKind.Explicit)]
internal struct RID_DEVICE_INFO
{
[System.Runtime.InteropServices.FieldOffset(0)]
public int cbSize;
[System.Runtime.InteropServices.FieldOffset(0)]
public int dwType;

[System.Runtime.InteropServices.FieldOffset(8)]
public RID_DEVICE_INFO_MOUSE mouse;
[System.Runtime.InteropServices.FieldOffset(8)]
public RID_DEVICE_INFO_KEYBOARD keyboard;
[System.Runtime.InteropServices.FieldOffset(8)]
public RID_DEVICE_INFO_HID hid;
}


Then basically I call the GetRawInputDeviceInfo and try to create a
RID_DEVICE_INFO from the resulting pointer. I think this is what is going
wrong:

GetRawInputDeviceInfo(rid.hDevice, RIDI_DEVICEINFO, IntPtr.Zero, ref
pcbSize);
if (pcbSize > 0)
{
//Try getting Device Info
RID_DEVICE_INFO ridi = new RID_DEVICE_INFO();
ridi.cbSize = pcbSize;
IntPtr pData = Marshal.AllocHGlobal((int)pcbSize);
GetRawInputDeviceInfo(rid.hDevice, RIDI_DEVICEINFO,
pData, ref pcbSize);
ridi = (RID_DEVICE_INFO)Marshal.PtrToStructure(pData,
typeof(RID_DEVICE_INFO)); ///Problematic line
Marshal.FreeHGlobal(pData);

if (ridi.dwType == RIM_TYPEHID)
{
System.Diagnostics.Debug.WriteLine("UsagePage: " +
ridi.hid.usUsagePage);
System.Diagnostics.Debug.WriteLine("Usage: " +
ridi.hid.usUsage);
}
}

Marshalling the Pointer to the info data into the info structure just
seems to return junk. It's the same junk each time, but junk. For example
the dwType in the ridi should match the one in the rid and be 0,1, or 2.
But the ridi.dwType often is some large number. It seems as if I can't
marshal the pointer properly or the struct that I'm using is messed up in
someway and is unable to accept the marshalled data. I don't know which
side I've gotten wrong.

Anyone have any helpful pointers for me? Also if you think this topic
belongs in a different newsgroup left me know.

Thanks,

Jason



I don't see where this pcbSize comes from, ridi.cbSize should hold the size
of the structure ridi structure, something you can get at like this:

ridi.cbSize = Marshal.SizeOf(ridi);

Also, you don't check the return value from the API call
(GetRawInputDeviceInfo), what makes you so sure that the call was
successful?


Willy.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top