2015-01-23 1 views
1

Я потратил часы и до сих пор не могу понять, почему вызов метода HidP_GetButtonCaps (из hid.dll) терпит неудачу при использовании Interop в C#.Ошибка при вызове процедуры HidP_GetButtonCaps с C#

Я перечисляю устройства и пытаюсь получить ButtonCaps и так далее. Но при вызове HidP_GetButtonCaps (или HidP_GetValueCaps) функция extern возвращает ошибку HIDP_STATUS_INVALID_REPORT_TYPE. И я просто не понимаю ... параметр типа отчета в этой подпрограмме - значение перечисления, как он может терпеть неудачу?

Вот несколько примеров кода. Я не стану все, потому что это долго. Конечно, если нужно добавить больше деталей, я добавлю.

В коде "// REMARK" есть комментарии: - Замечание 1: параметр объекта hidDevice исходит из другого метода. Я знаю, что содержимое полей «DevicePath», «prepsedData» и «ButtonCaps» корректно проверяется в режиме отладки. - Замечание 2: здесь у меня есть проблема. Я пробовал 3 разных способа аргумента: с объектом HIDP_REPORT_TYPE, непосредственно с HIDP_REPORT_TYPE.HidP_Input или «0», и это не имеет никакого значения ...

Большое спасибо за помощь.

структуры, константы, перечисления ...:

public enum HIDP_REPORT_TYPE : ushort 
    { 
     HidP_Input, 
     HidP_Output, 
     HidP_Feature 
    } 

    public struct ButtonCapsRange 
    { 
     public ushort UsageMin; 
     public ushort UsageMax; 
     public ushort StringMin; 
     public ushort StringMax; 
     public ushort DesignatorMin; 
     public ushort DesignatorMax; 
     public ushort DataIndexMin; 
     public ushort DataIndexMax; 
    } 

    public struct ButtonCapsNotRange 
    { 
     public ushort Usage; 
     public ushort Reserved1; 
     public ushort StringIndex; 
     public ushort Reserved2; 
     public ushort DesignatorIndex; 
     public ushort Reserved3; 
     public ushort DataIndex; 
     public ushort Reserved4; 
    } 

    [StructLayout(LayoutKind.Explicit)] 
    public struct HIDP_BUTTON_CAPS 
    { 
     [FieldOffset(0)] 
     public ushort UsagePage; 
     [FieldOffset(2)] 
     public byte ReportID; 
     [FieldOffset(3)] 
     public bool IsAlias; 
     [FieldOffset(4)] 
     public ushort BitField; 
     [FieldOffset(6)] 
     public ushort LinkCollection; 
     [FieldOffset(8)] 
     public ushort LinkUsage; 
     [FieldOffset(10)] 
     public ushort LinkUsagePage; 
     [FieldOffset(12)] 
     public bool IsRange; 
     [FieldOffset(13)] 
     public bool IsStringRange; 
     [FieldOffset(14)] 
     public bool IsDesignatorRange; 
     [FieldOffset(15)] 
     public bool IsAbsolute; 
     [FieldOffset(16)] 
     public uint[] Reserved; 
     [FieldOffset(16 + 10 * 4)] 
     public ButtonCapsRange Range; 
     [FieldOffset(16 + 10 * 4)] 
     public ButtonCapsNotRange NotRange; 
    } 

    public struct HID_DEVICE 
    { 
     public String DevicePath; 
     public IntPtr pHidDevice; // A file handle to the hid device. 
     public bool OpenedForRead; 
     public bool OpenedForWrite; 
     public bool OpenedOverlapped; 
     public bool OpenedExclusive; 
     public IntPtr Ppd; // The opaque parser info describing this device 
     public HIDP_CAPS Caps; // The Capabilities of this hid device. 
     public HIDD_ATTRIBUTES Attributes; 
     public byte[] pInputReportBuffer; 
     public HID_DATA[] InputData; // array of hid data structures 
     public ulong InputDataLength; // Num elements in this array. 
     public HIDP_BUTTON_CAPS[] pInputButtonCaps; 
     public HIDP_VALUE_CAPS[] pInputValueCaps; 
     public byte[] pOutputReportBuffer; 
     public HID_DATA[] pOutputData; 
     public ulong OutputDataLength; 
     public HIDP_BUTTON_CAPS[] pOutputButtonCaps; 
     public HIDP_VALUE_CAPS[] pOutputValueCaps; 
     public byte[] pFeatureReportBuffer; 
     public HID_DATA[] pFeatureData; 
     public ulong FeatureDataLength; 
     public HIDP_BUTTON_CAPS[] pFeatureButtonCaps; 
     public HIDP_VALUE_CAPS[] pFeatureValueCaps; 
    } 

внешние методы:

вызова метода:

private static bool FillDeviceInfo(ref HID_DEVICE hidDevice) 
    { 
     //REMARK 1 

     ulong numValues; 
     ushort numCaps; 
     HIDP_BUTTON_CAPS[] buttonCaps; 
     HIDP_VALUE_CAPS[] valueCaps; 
     HID_DATA[] data; 
     ulong i; 
     ushort usage; 
     uint dataIdx; 

     hidDevice.pInputReportBuffer = new byte[hidDevice.Caps.InputReportByteLength]; 

     buttonCaps = new HIDP_BUTTON_CAPS[hidDevice.Caps.NumberInputButtonCaps]; 
     //for(int a=0;a<buttonCaps.Length ;a++) 
     // buttonCaps[a].Reserved = new uint[10]; 
     hidDevice.pInputButtonCaps = buttonCaps; 

     valueCaps = new HIDP_VALUE_CAPS[hidDevice.Caps.NumberInputValueCaps]; 
     hidDevice.pInputValueCaps = valueCaps; 

     numCaps = hidDevice.Caps.NumberInputButtonCaps; 

     if (numCaps > 0) 
     { 
      //REMARK 2 
      HIDP_REPORT_TYPE reportType = HIDP_REPORT_TYPE.HidP_Input; 
      int val = (HidP_GetButtonCaps(reportType, ref buttonCaps, ref numCaps, hidDevice.Ppd)); 
      if (HIDP_STATUS_SUCCESS != val) 
      { 
       return false; 
      } 
     } 
//other stuff and retur true at end 
    } 

ответ

1

OK нашел проблему ... глупо как часто.

Я решил проблему ошибки «неправильного типа отчета», удалив «: ushort» в определении перечисления. Я думал, что это 2 байта данных в C, но это были 4 байта данных.

Кроме того, возникла проблема с работой со столами, сделанными в управляемой памяти в HidP_GetButtonCaps.

Вместо использования массива HIDP_BUTTON_CAPS (инициализированного в управляемой памяти) в HidP_GetButtonCaps, я использую IntPtr, ссылаясь на неуправляемую зону памяти.

+0

У вас есть рабочее приложение C#, читающее состояние геймпада? Я ищу, как сумасшедший, для альтернативы DirectInput, чтобы выполнить это, и эта тема тем ближе, когда я нашел решение. Необходимо включить этот файл «hid.dll» вместе с файлами приложения? Или это стандартная dll для Windows? –

+0

Привет, вы можете просто сделать ссылку на dll. Например: [DllImport («hid.dll», SetLastError = true)] [SecurityPermission (SecurityAction.Assert, Unrestricted = true)] static extern void HidD_GetHidGuid (ref Guid guid); У меня нет рабочего приложения, читающего состояние геймпада, мое приложение считывает входные данные с сырым сенсорным экраном. Я могу поделиться им с вами, если это поможет. – Pierre