HID FileStream在Windows 7上不工作

问题描述 投票:0回答:2

在我的开发机器中,我使用Windows 10创建了一个WPF,它可以接收和发送缓冲区到我的HID设备(自定义游戏控制器)。

它在我尝试的任何Windows 10上都能很好地工作,但我的一些客户运行Windows 7(无法升级),我无法让它工作。

写入方法抛出异常。

提供的用户缓冲区对请求的操作无效。

    public static bool SendBufferToDevice(HIDDev device, byte[] buffer)
    {
        try
        {
            lock (device)
            {
                device.fileStream.Write(buffer, 0, buffer.Length);
            }
                return true;
        }
        catch(Exception e)
        {
            return false;
        }
    }

读取方法抛出同样的异常。

提供的用户缓冲区对请求的操作无效。

    public static byte[] ReceiveBufferFromDevice(HIDDev device, int bufferSize)
    {
        byte[] buffer = new byte[bufferSize];
        try
        {
            using (MemoryStream ms = new MemoryStream())
            {
                int read = device.fileStream.Read(buffer, 0, buffer.Length);
                ms.Write(buffer, 0, read);
                return ms.ToArray();
            }
        }
        catch (Exception e)
        {
            return buffer;
        }
    }

我试着改变我发送的缓冲区的大小和类型,但没有成功。另外,如前所述,这段代码在Windows 10上也能正常工作。

HIDDev类的一部分。

public class HIDDev : IDisposable
    {

        // device handle
        private IntPtr handle;
        // safe file handle
        SafeFileHandle shandle;
        // stream
        private FileStream _fileStream;
        public FileStream fileStream 
        {
          get { return _fileStream; }
          /* do not expose this setter */
          internal set { _fileStream = value; }
        }


...

  }

有什么我需要做的只适用于< w10版本的吗?

编辑过了。

如上所述,HID类:

Native.cs -HIDInfo.cs

using System;
using System.Runtime;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Text;
using Microsoft.Win32.SafeHandles;


namespace HIDRealdrive
{
    class Native
    {
        /* invalid handle value */
        public static IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);


        #region kernel32.dll


        /* read access */
        public const uint GENERIC_READ = 0x80000000;
        /* write access */
        public const uint GENERIC_WRITE = 0x40000000;
        /* Enables subsequent open operations on a file or device to request 
         * write access.*/
        public const uint FILE_SHARE_WRITE = 0x2;
        /* Enables subsequent open operations on a file or device to request
         * read access. */
        public const uint FILE_SHARE_READ = 0x1;
        /* The file or device is being opened or created for asynchronous I/O. */
        public const uint FILE_FLAG_OVERLAPPED = 0x40000000;
        /* Opens a file or device, only if it exists. */
        public const uint OPEN_EXISTING = 3;
        /* Opens a file, always. */
        public const uint OPEN_ALWAYS = 4;

        [DllImport("kernel32.dll", SetLastError = true)]
        /* opens files that access usb hid devices */
        public static extern IntPtr CreateFile(
            [MarshalAs(UnmanagedType.LPStr)] string strName, 
            uint nAccess, uint nShareMode, IntPtr lpSecurity, 
            uint nCreationFlags, uint nAttributes, IntPtr lpTemplate);

        [DllImport("kernel32.dll", SetLastError = true)]
        /* closes file */
        public static extern bool CloseHandle(IntPtr hObject);

        [DllImport("kernel32.dll")]
        static public extern int WriteFile(IntPtr hFile, ref byte lpBuffer, int nNumberOfBytesToWrite);

        [DllImport("kernel32.dll")]
        static public extern bool ReadFile(IntPtr hFile, ref byte lpBuffer, int nNumberOfBytesToRead);

        #endregion
        #region hid.dll


        /* The HIDD_ATTRIBUTES structure contains vendor information about a 
         * HIDClass device.*/
        [StructLayout(LayoutKind.Sequential)]
        public struct HiddAttributtes
        {
            /* size in bytes */
            public Int32 Size;
            /* vendor id */
            public Int16 VendorID;
            /* product id */
            public Int16 ProductID;
            /* hid vesion number */
            public Int16 VersionNumber;
        }

        //Capacidades totais do Dispositivo
        public struct HIDP_CAPS
        {
            public Int16 Usage;
            public Int16 UsagePage;
            public Int16 InputReportByteLength;
            public Int16 OutputReportByteLength;
            public Int16 FeatureReportByteLength;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)]
            public Int16[] Reserved;
            public Int16 NumberLinkCollectionNodes;
            public Int16 NumberInputButtonCaps;
            public Int16 NumberInputValueCaps;
            public Int16 NumberInputDataIndices;
            public Int16 NumberOutputButtonCaps;
            public Int16 NumberOutputValueCaps;
            public Int16 NumberOutputDataIndices;
            public Int16 NumberFeatureButtonCaps;
            public Int16 NumberFeatureValueCaps;
            public Int16 NumberFeatureDataIndices;
        }



        [DllImport("hid.dll", SetLastError = true)]
        /* gets HID class Guid */
        public static extern void HidD_GetHidGuid(out Guid gHid);

        /* gets hid device attributes */
        [DllImport("hid.dll", SetLastError = true)]
        public static extern Boolean HidD_GetAttributes(IntPtr hFile,
            ref HiddAttributtes attributes);

        /* gets usb manufacturer string */
        [DllImport("hid.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern Boolean HidD_GetManufacturerString(IntPtr hFile,
            StringBuilder buffer, Int32 bufferLength);

        /* gets product string */
        [DllImport("hid.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern Boolean HidD_GetProductString(IntPtr hFile,
            StringBuilder buffer, Int32 bufferLength);

        /* gets serial number string */
        [DllImport("hid.dll", CharSet = CharSet.Auto, SetLastError = true)]
        internal static extern bool HidD_GetSerialNumberString(IntPtr hDevice,
            StringBuilder buffer, Int32 bufferLength);

        //Novos Imports do GenericHid_62
        [DllImport("hid.dll", SetLastError = true)]
        internal static extern Boolean HidD_FlushQueue(SafeFileHandle HidDeviceObject);

        [DllImport("hid.dll", SetLastError = true)]
        internal static extern Boolean HidD_FreePreparsedData(IntPtr PreparsedData);

        [DllImport("hid.dll", SetLastError = true)]
        internal static extern Boolean HidD_GetFeature(SafeFileHandle HidDeviceObject, Byte[] lpReportBuffer,
                                                       Int32 ReportBufferLength);

        [DllImport("hid.dll", SetLastError = true)]
        internal static extern Boolean HidD_GetInputReport(SafeFileHandle HidDeviceObject, Byte[] lpReportBuffer,
                                                           Int32 ReportBufferLength);

        [DllImport("hid.dll", SetLastError = true)]
        internal static extern Boolean HidD_GetNumInputBuffers(SafeFileHandle HidDeviceObject, ref Int32 NumberBuffers);

        [DllImport("hid.dll", SetLastError = true)]
        internal static extern Boolean HidD_GetPreparsedData(SafeFileHandle HidDeviceObject, ref IntPtr PreparsedData);

        [DllImport("hid.dll", SetLastError = true)]
        internal static extern Boolean HidD_SetFeature(SafeFileHandle HidDeviceObject, Byte[] lpReportBuffer,
                                                       Int32 ReportBufferLength);

        [DllImport("hid.dll", SetLastError = true)]
        internal static extern Boolean HidD_SetNumInputBuffers(SafeFileHandle HidDeviceObject, Int32 NumberBuffers);

        [DllImport("hid.dll", SetLastError = true)]
        internal static extern Boolean HidD_SetOutputReport(SafeFileHandle HidDeviceObject, Byte[] lpReportBuffer,
                                                            Int32 ReportBufferLength);

        [DllImport("hid.dll", SetLastError = true)]
        internal static extern Int32 HidP_GetCaps(IntPtr PreparsedData, ref HIDP_CAPS Capabilities);

        [DllImport("hid.dll", SetLastError = true)]
        internal static extern Int32 HidP_GetValueCaps(Int32 ReportType, Byte[] ValueCaps, ref Int32 ValueCapsLength,
                                                       IntPtr PreparsedData);


        #endregion
        #region setupapi.dll


        /* Return only devices that are currently present in a system. */
        public const int DIGCF_PRESENT = 0x02;
        /* Return devices that support device interfaces for the specified 
         * device interface classes. */
        public const int DIGCF_DEVICEINTERFACE = 0x10;

        /* structure returned by SetupDiEnumDeviceInterfaces */
        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        public struct DeviceInterfaceData
        {
            /* size of fixed part of structure */
            public int Size;
            /* The GUID for the class to which the device interface belongs. */
            public Guid InterfaceClassGuid;
            /* Can be one or more of the following: SPINT_ACTIVE, 
             * SPINT_DEFAULT, SPINT_REMOVED */
            public int Flags;
            /* do not use */
            public IntPtr Reserved;
        }

        /* A structure contains the path for a device interface.*/
        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        public struct DeviceInterfaceDetailData
        {
            /* size of fixed part of structure */
            public int Size;
            /* device path, as to be used by CreateFile */
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)]
            public string DevicePath;
        }

        /* function returns a handle to a device information set that contains
         * requested device information elements for a local computer */
        [DllImport("setupapi.dll", SetLastError = true)]
        public static extern IntPtr SetupDiGetClassDevs(ref Guid gClass, 
            [MarshalAs(UnmanagedType.LPStr)] string strEnumerator, 
            IntPtr hParent, uint nFlags);

        /* The function enumerates the device interfaces that are contained in 
         * a device information set.*/
        [DllImport("setupapi.dll", SetLastError = true)]
        public static extern bool SetupDiEnumDeviceInterfaces(
            IntPtr lpDeviceInfoSet, uint nDeviceInfoData, ref Guid gClass,
            uint nIndex, ref DeviceInterfaceData oInterfaceData);

        /* The SetupDiGetDeviceInterfaceDetail function returns details about 
         * a device interface.*/
        [DllImport("setupapi.dll", SetLastError = true)]
        public static extern bool SetupDiGetDeviceInterfaceDetail(
            IntPtr lpDeviceInfoSet, ref DeviceInterfaceData oInterfaceData,
            ref DeviceInterfaceDetailData oDetailData, 
            uint nDeviceInterfaceDetailDataSize, ref uint nRequiredSize,
            IntPtr lpDeviceInfoData);

        /* destroys device list */
        [DllImport("setupapi.dll", SetLastError = true)]
        public static extern bool SetupDiDestroyDeviceInfoList(IntPtr lpInfoSet);


        #endregion

    }
}

HIDInfo.cs

namespace HIDRealdrive
{
    public class HIDInfo
    {
        /* device path */
        public string Path { get; private set; }
        /* vendor ID */
        public short Vid { get; private set; }
        /* product id */
        public short Pid { get; private set; }
        /* usb product string */
        public string Product { get; private set; }
        /* usb manufacturer string */
        public string Manufacturer { get; private set; }
        /* usb serial number string */
        public string SerialNumber { get; private set; }

        /* constructor */
        public HIDInfo(string product, string serial, string manufacturer, 
            string path, short vid, short pid)
        {
            /* copy information */
            Product = product;
            SerialNumber = serial;
            Manufacturer = manufacturer;
            Path = path;
            Vid = vid;
            Pid = pid;
        }
    }
}

HIDDev.cs

using System;
using System.IO;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Win32.SafeHandles;
using System.Diagnostics;


namespace HIDRealdrive
{
    public class HIDDev : IDisposable
    {

        /* device handle */
        private IntPtr handle;
        /* safe file handle */
        SafeFileHandle shandle;
        /* stream */
        private FileStream _fileStream;
        //conectado
        private bool isConnected = false;

        internal Native.HIDP_CAPS Capabilities;
        private string[] capabilitiesStrings = new string[16];

        //Retorna a conexão
        public bool IsConnected { get { return isConnected; } }


        /* stream */
        public FileStream fileStream 
        {
            get { return _fileStream; }
            /* do not expose this setter */
            internal set { _fileStream = value; }
        }

        /* dispose */
        public void Dispose()
        {
            /* deal with file stream */
            if (_fileStream != null) {
                /* close stream */
                _fileStream.Close();
                /* get rid of object */
                _fileStream = null;
            }

            /* close handle */
            Native.CloseHandle(handle);
        }

        /* open hid device */
        public bool Open(HIDInfo dev)
        {


            /* opens hid device file */
            handle = Native.CreateFile(dev.Path, 
                Native.GENERIC_READ | Native.GENERIC_WRITE,
                Native.FILE_SHARE_READ | Native.FILE_SHARE_WRITE,
                IntPtr.Zero, Native.OPEN_EXISTING, Native.FILE_FLAG_OVERLAPPED,
                IntPtr.Zero);

            /* whops */
            if (handle == Native.INVALID_HANDLE_VALUE) {
                isConnected = false;
                return false;
            }
            isConnected = true;

            /* build up safe file handle */
            shandle = new SafeFileHandle(handle, false);

            capabilitiesStrings = GetDeviceCapabilities(shandle);
            /* prepare stream - async */
            _fileStream = new FileStream(shandle, FileAccess.ReadWrite, 
                32, true);

            /* report status */
            return true;
        }

        /*Recebe informações totais do Dispositivo*/

        string[] GetDeviceCapabilities(SafeFileHandle hidHandle)
        {
            var preparsedData = new IntPtr();
            string[] capabilitiesStrings = new string[16];

            try
            {
                //  ***
                //  API function: HidD_GetPreparsedData

                //  Purpose: retrieves a pointer to a buffer containing information about the device's capabilities.
                //  HidP_GetCaps and other API functions require a pointer to the buffer.

                //  Requires: 
                //  A handle returned by CreateFile.
                //  A pointer to a buffer.

                //  Returns:
                //  True on success, False on failure.
                //  ***

                Native.HidD_GetPreparsedData(hidHandle, ref preparsedData);

                //  ***
                //  API function: HidP_GetCaps

                //  Purpose: find out a device's capabilities.
                //  For standard devices such as joysticks, you can find out the specific
                //  capabilities of the device.
                //  For a custom device where the software knows what the device is capable of,
                //  this call may be unneeded.

                //  Accepts:
                //  A pointer returned by HidD_GetPreparsedData
                //  A pointer to a HIDP_CAPS structure.

                //  Returns: True on success, False on failure.
                //  ***

                Int32 result = Native.HidP_GetCaps(preparsedData, ref Capabilities);
                if ((result != 0))
                {
                    Debug.WriteLine("");
                    Debug.WriteLine("  Usage: " + Convert.ToString(Capabilities.Usage, 16));
                    Debug.WriteLine("  Usage Page: " + Convert.ToString(Capabilities.UsagePage, 16));
                    Debug.WriteLine("  Input Report Byte Length: " + Capabilities.InputReportByteLength);
                    Debug.WriteLine("  Output Report Byte Length: " + Capabilities.OutputReportByteLength);
                    Debug.WriteLine("  Feature Report Byte Length: " + Capabilities.FeatureReportByteLength);
                    Debug.WriteLine("  Number of Link Collection Nodes: " + Capabilities.NumberLinkCollectionNodes);
                    Debug.WriteLine("  Number of Input Button Caps: " + Capabilities.NumberInputButtonCaps);
                    Debug.WriteLine("  Number of Input Value Caps: " + Capabilities.NumberInputValueCaps);
                    Debug.WriteLine("  Number of Input Data Indices: " + Capabilities.NumberInputDataIndices);
                    Debug.WriteLine("  Number of Output Button Caps: " + Capabilities.NumberOutputButtonCaps);
                    Debug.WriteLine("  Number of Output Value Caps: " + Capabilities.NumberOutputValueCaps);
                    Debug.WriteLine("  Number of Output Data Indices: " + Capabilities.NumberOutputDataIndices);
                    Debug.WriteLine("  Number of Feature Button Caps: " + Capabilities.NumberFeatureButtonCaps);
                    Debug.WriteLine("  Number of Feature Value Caps: " + Capabilities.NumberFeatureValueCaps);
                    Debug.WriteLine("  Number of Feature Data Indices: " + Capabilities.NumberFeatureDataIndices);

                    capabilitiesStrings[0]=("Full Device Capabilities Report:");
                    capabilitiesStrings[1] = ("  Usage: " + Convert.ToString(Capabilities.Usage, 16));
                    capabilitiesStrings[2] = ("  Usage Page: " + Convert.ToString(Capabilities.UsagePage, 16));
                    capabilitiesStrings[3] = ("  Input Report Byte Length: " + Capabilities.InputReportByteLength);
                    capabilitiesStrings[4] = ("  Output Report Byte Length: " + Capabilities.OutputReportByteLength);
                    capabilitiesStrings[5] = ("  Feature Report Byte Length: " + Capabilities.FeatureReportByteLength);
                    capabilitiesStrings[6] = ("  Number of Link Collection Nodes: " + Capabilities.NumberLinkCollectionNodes);
                    capabilitiesStrings[7] = ("  Number of Input Button Caps: " + Capabilities.NumberInputButtonCaps);
                    capabilitiesStrings[8] = ("  Number of Input Value Caps: " + Capabilities.NumberInputValueCaps);
                    capabilitiesStrings[9] = ("  Number of Input Data Indices: " + Capabilities.NumberInputDataIndices);
                    capabilitiesStrings[10] = ("  Number of Output Button Caps: " + Capabilities.NumberOutputButtonCaps);
                    capabilitiesStrings[11] = ("  Number of Output Value Caps: " + Capabilities.NumberOutputValueCaps);
                    capabilitiesStrings[12] = ("  Number of Output Data Indices: " + Capabilities.NumberOutputDataIndices);
                    capabilitiesStrings[13] = ("  Number of Feature Button Caps: " + Capabilities.NumberFeatureButtonCaps);
                    capabilitiesStrings[14] = ("  Number of Feature Value Caps: " + Capabilities.NumberFeatureValueCaps);
                    capabilitiesStrings[15] = ("  Number of Feature Data Indices: " + Capabilities.NumberFeatureDataIndices);
                    //  ***
                    //  API function: HidP_GetValueCaps

                    //  Purpose: retrieves a buffer containing an array of HidP_ValueCaps structures.
                    //  Each structure defines the capabilities of one value.
                    //  This application doesn't use this data.

                    //  Accepts:
                    //  A report type enumerator from hidpi.h,
                    //  A pointer to a buffer for the returned array,
                    //  The NumberInputValueCaps member of the device's HidP_Caps structure,
                    //  A pointer to the PreparsedData structure returned by HidD_GetPreparsedData.

                    //  Returns: True on success, False on failure.
                    //  ***                    

                    Int32 vcSize = Capabilities.NumberInputValueCaps;
                    var valueCaps = new Byte[vcSize];

                    //Native.HidP_GetValueCaps(Native.HidP_Input, valueCaps, ref vcSize, preparsedData);

                    // (To use this data, copy the ValueCaps byte array into an array of structures.)              
                }
            }

            catch (Exception ex)
            {
                throw;
            }
            finally
            {
                //  ***
                //  API function: HidD_FreePreparsedData

                //  Purpose: frees the buffer reserved by HidD_GetPreparsedData.

                //  Accepts: A pointer to the PreparsedData structure returned by HidD_GetPreparsedData.

                //  Returns: True on success, False on failure.
                //  ***

                if (preparsedData != IntPtr.Zero)
                {
                    Native.HidD_FreePreparsedData(preparsedData);
                }
            }
            return capabilitiesStrings;
        }

        /* close hid device */
        public void Close()
        {
            /* deal with file stream */
            if (_fileStream != null) {
                /* close stream */
                _fileStream.Close();
                /* get rid of object */
                _fileStream = null;
            }

            /* close handle */
            Native.CloseHandle(handle);
            isConnected = false;
        }

        /* write record */
        public void Write(byte[] data)
        {

            /* Cria task e write some bytes */ 
            fileStream.Write(data, 0, data.Length);
            /* flush! */
            _fileStream.Flush();
        }

        public async Task WriteAsync(byte[] data)
        {
            /* Cria task e write some bytes */
            Task t =_fileStream.WriteAsync(data, 0, data.Length);
            await t;
            /* flush! */
            _fileStream.Flush();
        }

        /* read record */
        public void Read(byte[] data)
        {
            /* get number of bytes */
            int n = 0, bytes = data.Length;

            /* read buffer */
            while (n != bytes) {
                /* read data */
                int rc = _fileStream.Read(data, n, bytes - n);
                /* update pointers */
                n += rc;
            }
        }

        public byte[] GetInputReport(byte[] inBuffer, int buffLenght)
        {
            Native.HidD_GetInputReport(shandle, inBuffer, buffLenght);
            return inBuffer;

        }

        /*Mais info sobre a placa*/

        public string[] GetFullDeviceCapabilities(string[] cap)
        {
            return cap;

        }

        public string GetFullDeviceCapabilitiesString()
        {
            string capabilities = "";

            for (int i = 0; i <= capabilitiesStrings.Length-1; i++)
            {
                capabilities = capabilities + capabilitiesStrings[i];
            }

            return capabilities;

        }

    }
}
c# winapi windows-7 hid
2个回答
0
投票

刚刚停止尝试重新发明轮子,并使用了的。

HidSharp

https:/www.zer7.comsoftwarehidsharp

而且效果不错。


0
投票

获取设备功能,它会说输入和输出报告的大小,你必须让你的缓冲器匹配这个大小。

你必须让你的缓冲器匹配这个大小。

老实说,我已经放弃了在Win 7上使用文件流的尝试,因为它们一直挂在内核中等待半岸。

使用HIDAPI和interop这些调用。(不确定,但认为这可能是HidSharp已经做的事情?)

https:/docs.microsoft.comen-uswindows-hardwaredrivershidintroduction-to-hid-concepts。

© www.soinside.com 2019 - 2024. All rights reserved.