Hello,
I believe your issue is with you array initialization. You initialize it to 255 elements without checking to see if there are actually 255 valuecaps. The result is you get junk on the array elements beyond the actual valuecaps count. Assuming that you got most of what you want, below is the structure definitions and imports to use.
public const int HIDP_STATUS_SUCCESS = (0x0 << 28) | (0x11 << 16) | 0;
public enum HIDP_REPORT_TYPE
{
HidP_Input = 0,
HidP_Output = 1,
HidP_Feature = 2,
}
[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct HidCaps
{
public UInt16 Usage;
public UInt16 UsagePage;
public UInt16 InputReportByteLength;
public UInt16 OutputReportByteLength;
public UInt16 FeatureReportByteLength;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)]
public UInt16[] Reserved;
public UInt16 NumberLinkCollectionNodes;
public UInt16 NumberInputButtonCaps;
public UInt16 NumberInputValueCaps;
public UInt16 NumberInputDataIndices;
public UInt16 NumberOutputButtonCaps;
public UInt16 NumberOutputValueCaps;
public UInt16 NumberOutputDataIndices;
public UInt16 NumberFeatureButtonCaps;
public UInt16 NumberFeatureValueCaps;
public UInt16 NumberFeatureDataIndices;
}
[StructLayout(LayoutKind.Sequential, Pack=4)]
public struct HidP_Range
{
public UInt16 UsageMin;
public UInt16 UsageMax;
public UInt16 StringMin;
public UInt16 StringMax;
public UInt16 DesignatorMin;
public UInt16 DesignatorMax;
public UInt16 DataIndexMin;
public UInt16 DataIndexMax;
}
[StructLayout(LayoutKind.Sequential, Pack=4)]
public struct HidP_NotRange
{
public UInt16 Usage;
public UInt16 Reserved1;
public UInt16 StringIndex;
public UInt16 Reserved2;
public UInt16 DesignatorIndex;
public UInt16 Reserved3;
public UInt16 DataIndex;
public UInt16 Reserved4;
}
[StructLayout(LayoutKind.Explicit, CharSet=CharSet.Ansi, Pack=4)]
public struct HidP_Button_Caps
{
[FieldOffset(0)]
public UInt16 UsagePage;
[FieldOffset(2)]
public byte ReportID;
[FieldOffset(3), MarshalAs(UnmanagedType.U1)]
public bool IsAlias;
[FieldOffset(4)]
public UInt16 BitField;
[FieldOffset(6)]
public UInt16 LinkCollection;
[FieldOffset(8)]
public UInt16 LinkUsage;
[FieldOffset(10)]
public UInt16 LinkUsagePage;
[FieldOffset(12), MarshalAs(UnmanagedType.U1)]
public bool IsRange;
[FieldOffset(13), MarshalAs(UnmanagedType.U1)]
public bool IsStringRange;
[FieldOffset(14), MarshalAs(UnmanagedType.U1)]
public bool IsDesignatorRange;
[FieldOffset(15), MarshalAs(UnmanagedType.U1)]
public bool IsAbsolute;
[FieldOffset(16), MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public int[] Reserved;
// The Structs in the Union
[FieldOffset(56)]
public HidP_Range Range;
[FieldOffset(56)]
public HidP_NotRange NotRange;
}
[StructLayout(LayoutKind.Explicit, CharSet=CharSet.Ansi, Pack=4)]
public struct HidP_Value_Caps
{
[FieldOffset(0)]
public UInt16 UsagePage;
[FieldOffset(2)]
public byte ReportID;
[MarshalAs(UnmanagedType.I1)]
[FieldOffset(3)]
public bool IsAlias;
[FieldOffset(4)]
public UInt16 BitField;
[FieldOffset(6)]
public UInt16 LinkCollection;
[FieldOffset(8)]
public UInt16 LinkUsage;
[FieldOffset(10)]
public UInt16 LinkUsagePage;
[MarshalAs(UnmanagedType.I1)]
[FieldOffset(12)]
public bool IsRange;
[MarshalAs(UnmanagedType.I1)]
[FieldOffset(13)]
public bool IsStringRange;
[MarshalAs(UnmanagedType.I1)]
[FieldOffset(14)]
public bool IsDesignatorRange;
[MarshalAs(UnmanagedType.I1)]
[FieldOffset(15)]
public bool IsAbsolute;
[MarshalAs(UnmanagedType.I1)]
[FieldOffset(16)]
public bool HasNull;
[FieldOffset(17)]
public System.Char Reserved;
[FieldOffset(18)]
public UInt16 BitSize;
[FieldOffset(20)]
public UInt16 ReportCount;
[FieldOffset(22)]
public UInt16 Reserved2a;
[FieldOffset(24)]
public UInt16 Reserved2b;
[FieldOffset(26)]
public UInt16 Reserved2c;
[FieldOffset(28)]
public UInt16 Reserved2d;
[FieldOffset(30)]
public UInt16 Reserved2e;
[FieldOffset(32)]
public UInt64 UnitsExp;
[FieldOffset(36)]
public UInt64 Units;
[FieldOffset(40)]
public Int64 LogicalMin;
[FieldOffset(44)]
public Int64 LogicalMax;
[FieldOffset(48)]
public Int64 PhysicalMin;
[FieldOffset(52)]
public Int64 PhysicalMax;
// The Structs in the Union
[FieldOffset(56)]
public HidP_Range Range;
[FieldOffset(56)]
public HidP_NotRange NotRange;
}
[DllImport("hid.dll", SetLastError = true)]
public static extern bool HidD_GetPreparsedData(SafeFileHandle hFile, out IntPtr lpData);
[DllImport("hid.dll", SetLastError = true)]
public static extern int HidP_GetCaps(IntPtr lpData, out HidCaps oCaps);
[DllImport("hid.dll", SetLastError = true)]
public static extern bool HidD_FreePreparsedData(ref IntPtr pData);
[DllImport("hid.dll", SetLastError = true)]
public static extern int HidP_GetButtonCaps(HIDP_REPORT_TYPE reportType, [In, Out] HidP_Button_Caps[] buttonCaps, ref UInt16 buttonCapsLength, IntPtr preparsedData);
[DllImport("hid.dll", SetLastError = true)]
public static extern int HidP_GetValueCaps(HIDP_REPORT_TYPE reportType, [In, Out] HidP_Value_Caps[] valueCaps, ref UInt16 valueCapsLength, IntPtr preparsedData);
With these above definitions and assuming that you have a file handle opened using the createfile method, here is how to get the value caps.
IntPtr preparedData;
HidCaps hidCaps = null;
HidP_Button_Caps[] outputButtonCaps = null;
HidP_Value_Caps[] outputValueCaps = null;
HidP_Button_Caps[] inputButtonCaps = null;
HidP_Value_Caps[] inputValueCaps = null;
HidP_Button_Caps[] featureButtonCaps = null;
HidP_Value_Caps[] numberFeatureValueCaps = null;
try
{
if (HidD_GetPreparsedData(safeHandle, out preparedData))
{
if (HidP_GetCaps(preparedData, out hidCaps) != HIDP_STATUS_SUCCESS)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
var numberOutputButtonCaps = hidCaps.NumberOutputButtonCaps;
if (numberOutputButtonCaps != 0)
{
outputButtonCaps = new HidP_Button_Caps[numberOutputButtonCaps];
if (HidP_GetButtonCaps(HIDP_REPORT_TYPE.HidP_Output, outputButtonCaps, ref numberOutputButtonCaps, preparedData) != HIDP_STATUS_SUCCESS)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
var numberOutputValueCaps = hidCaps.NumberOutputValueCaps;
if (numberOutputValueCaps != 0)
{
outputValueCaps = new HidP_Value_Caps[numberOutputValueCaps];
if (HidP_GetValueCaps(HIDP_REPORT_TYPE.HidP_Output, outputValueCaps, ref numberOutputValueCaps, preparedData) != HIDP_STATUS_SUCCESS)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
var numberInputButtonCaps = hidCaps.NumberInputButtonCaps;
if (numberInputButtonCaps != 0)
{
inputButtonCaps = new HidP_Button_Caps[numberInputButtonCaps];
if (HidP_GetButtonCaps(HIDP_REPORT_TYPE.HidP_Input, inputButtonCaps, ref numberInputButtonCaps, preparedData) != HIDP_STATUS_SUCCESS)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
var numberInputValueCaps = hidCaps.NumberInputValueCaps;
if (numberInputValueCaps != 0)
{
inputValueCaps = new HidP_Value_Caps[numberInputValueCaps];
if (HidP_GetValueCaps(HIDP_REPORT_TYPE.HidP_Input, inputValueCaps, ref numberInputValueCaps, preparedData) != HIDP_STATUS_SUCCESS)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
var numberFeatureButtonCaps = hidCaps.NumberFeatureButtonCaps;
if (numberFeatureButtonCaps != 0)
{
featureButtonCaps = new HidP_Button_Caps[numberFeatureButtonCaps];
if (HidP_GetButtonCaps(HIDP_REPORT_TYPE.HidP_Feature, featureButtonCaps, ref numberFeatureButtonCaps, preparedData) != HIDP_STATUS_SUCCESS)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
var numberFeatureValueCaps = hidCaps.NumberFeatureValueCaps;
if (numberFeatureValueCaps != 0)
{
featureValueCaps = new HidP_Value_Caps[numberFeatureValueCaps];
if (HidP_GetValueCaps(HIDP_REPORT_TYPE.HidP_Feature, featureValueCaps, ref numberFeatureValueCaps, preparedData) != HIDP_STATUS_SUCCESS)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
}
}
catch (Win32Exception)
{
throw;
}
finally
{
if(preparedData != IntPtr.Zero)
HidD_FreePreparsedData(ref preparedData)
}