zoukankan      html  css  js  c++  java
  • 使用C#使用Windows的HID通信

    Windows使用HID通信相对比较简单,HID都是通过PID、VID信息来查找连接的,相比于串口,几乎无变化,连接无需人工选择,十分方便,也不需要驱动。

    下面上实例,PID为0x003f,VID为0x04D8,支持发送接收数据显示到UI,使用C#来编写,调用的是windows api(create file、read file、write file)。

    本实例将HID接口分成3层,支持自动连接、断开状态通知,异步收发数据,单个数据包大小为64bytes(因为从设备的数据包设定为64bytes,保持一致)。

    接口分为两层,第一层将create file、read file、write file封装,第二层再封装自动连接、异步收发。

    HID.cs -> HIDInterface.cs -> 应用

    注意,这里所有数据都是64bytes,但是有用数据并非这么多,所以设定为第一个数据为后面数据实际长度,若需要修改定义,请在HIDInterface.cs的Send与HidDataReceived函数中修改处理方法即可。

    HID.cs

    using System;
    using System.Collections.Generic;
    using System.Runtime.InteropServices;
    using System.IO;
    using Microsoft.Win32.SafeHandles;
    using System.Windows;
    
    namespace HID_SIMPLE.HID
    {
        public class report : EventArgs
        {
            public readonly byte reportID;
            public readonly byte[] reportBuff;
            public report(byte id, byte[] arrayBuff)
            {
                reportID = id;
                reportBuff = arrayBuff;
            }
        }
        public class Hid : object
        {
            private IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
            private const int MAX_USB_DEVICES = 64;
            private bool deviceOpened = false;
            private FileStream hidDevice = null;
            private IntPtr hHubDevice;
    
            int outputReportLength;//输出报告长度,包刮一个字节的报告ID
            public int OutputReportLength { get { return outputReportLength; } }
            int inputReportLength;//输入报告长度,包刮一个字节的报告ID
            public int InputReportLength { get { return inputReportLength; } }
    
            /// <summary>
            /// 打开指定信息的设备
            /// </summary>
            /// <param name="vID">设备的vID</param>
            /// <param name="pID">设备的pID</param>
            /// <param name="serial">设备的serial</param>
            /// <returns></returns>
            public HID_RETURN OpenDevice(UInt16 vID, UInt16 pID, string serial)
            {
                if (deviceOpened == false)
                {
                    //获取连接的HID列表
                    List<string> deviceList = new List<string>();
                    GetHidDeviceList(ref deviceList);
                    if (deviceList.Count == 0)
                        return HID_RETURN.NO_DEVICE_CONECTED;
                    for (int i = 0; i < deviceList.Count; i++)
                    {
                        IntPtr device = CreateFile(deviceList[i],
                                                    DESIREDACCESS.GENERIC_READ | DESIREDACCESS.GENERIC_WRITE,
                                                    0,
                                                    0,
                                                    CREATIONDISPOSITION.OPEN_EXISTING,
                                                    FLAGSANDATTRIBUTES.FILE_FLAG_OVERLAPPED,
                                                    0);
                        if (device != INVALID_HANDLE_VALUE)
                        {
                            HIDD_ATTRIBUTES attributes;
                            IntPtr serialBuff = Marshal.AllocHGlobal(512);
                            HidD_GetAttributes(device, out attributes);
                            HidD_GetSerialNumberString(device, serialBuff, 512);
                            string deviceStr = Marshal.PtrToStringAuto(serialBuff);
                            Marshal.FreeHGlobal(serialBuff);
                            if (attributes.VendorID == vID && attributes.ProductID == pID && deviceStr.Contains(serial))
                            {
                                IntPtr preparseData;
                                HIDP_CAPS caps;
                                HidD_GetPreparsedData(device, out preparseData);
                                HidP_GetCaps(preparseData, out caps);
                                HidD_FreePreparsedData(preparseData);
                                outputReportLength = caps.OutputReportByteLength;
                                inputReportLength = caps.InputReportByteLength;
    
                                hidDevice = new FileStream(new SafeFileHandle(device, false), FileAccess.ReadWrite, inputReportLength, true);
                                deviceOpened = true;
                                BeginAsyncRead();
    
                                hHubDevice = device;
                                return HID_RETURN.SUCCESS;
                            }
                        }
                    }
                    return HID_RETURN.DEVICE_NOT_FIND;
                }
                else
                    return HID_RETURN.DEVICE_OPENED;
            }
    
            /// <summary>
            /// 关闭打开的设备
            /// </summary>
            public void CloseDevice()
            {
                if (deviceOpened == true)
                {
                    deviceOpened = false;
                    hidDevice.Close();
                }
            }
    
            /// <summary>
            /// 开始一次异步读
            /// </summary>
            private void BeginAsyncRead()
            {
                byte[] inputBuff = new byte[InputReportLength];
                hidDevice.BeginRead(inputBuff, 0, InputReportLength, new AsyncCallback(ReadCompleted), inputBuff);
            }
    
            /// <summary>
            /// 异步读取结束,发出有数据到达事件
            /// </summary>
            /// <param name="iResult">这里是输入报告的数组</param>
            private void ReadCompleted(IAsyncResult iResult)
            {
                byte[] readBuff = (byte[])(iResult.AsyncState);
                try
                {
                    hidDevice.EndRead(iResult);//读取结束,如果读取错误就会产生一个异常
                    byte[] reportData = new byte[readBuff.Length - 1];
                    for (int i = 1; i < readBuff.Length; i++)
                        reportData[i - 1] = readBuff[i];
                    report e = new report(readBuff[0], reportData);
                    OnDataReceived(e); //发出数据到达消息
                    if (!deviceOpened) return;
                    BeginAsyncRead();//启动下一次读操作
                }
                catch //读写错误,设备已经被移除
                {
                    //MyConsole.WriteLine("设备无法连接,请重新插入设备");
                    EventArgs ex = new EventArgs();
                    OnDeviceRemoved(ex);//发出设备移除消息
                    CloseDevice();
    
                }
            }
    
            public delegate void DelegateDataReceived(object sender, report e);
            //public event EventHandler<ConnectEventArg> StatusConnected;
    
            public DelegateDataReceived DataReceived;
    
            /// <summary>
            /// 事件:数据到达,处理此事件以接收输入数据
            /// </summary>
    
            protected virtual void OnDataReceived(report e)
            {
                if (DataReceived != null) DataReceived(this, e);
            }
    
            /// <summary>
            /// 事件:设备断开
            /// </summary>
    
            public delegate void DelegateStatusConnected(object sender, EventArgs e);
            public DelegateStatusConnected DeviceRemoved;
            protected virtual void OnDeviceRemoved(EventArgs e)
            {
                if (DeviceRemoved != null) DeviceRemoved(this,e);
            }
    
            /// <summary>
            ///
            /// </summary>
            /// <param name="buffer"></param>
            /// <returns></returns>
            public HID_RETURN Write(report r)
            {
                if (deviceOpened)
                {
                    try
                    {
                        byte[] buffer = new byte[outputReportLength];
                        buffer[0] = r.reportID;
                        int maxBufferLength = 0;
                        if (r.reportBuff.Length < outputReportLength - 1)
                            maxBufferLength = r.reportBuff.Length;
                        else
                            maxBufferLength = outputReportLength - 1;
    
                        for (int i = 0; i < maxBufferLength; i++)
                            buffer[i + 1] = r.reportBuff[i];
                        hidDevice.Write(buffer, 0, OutputReportLength);
                        return HID_RETURN.SUCCESS;
                    }
                    catch
                    {
                        EventArgs ex = new EventArgs();
                        OnDeviceRemoved(ex);//发出设备移除消息
                        CloseDevice();
                        return HID_RETURN.NO_DEVICE_CONECTED;
                    }
                }
                return HID_RETURN.WRITE_FAILD;
            }
    
            /// <summary>
            /// 获取所有连接的hid的设备路径
            /// </summary>
            /// <returns>包含每个设备路径的字符串数组</returns>
            public static void GetHidDeviceList(ref List<string> deviceList)
            {
                Guid hUSB = Guid.Empty;
                uint index = 0;
    
                deviceList.Clear();
                // 取得hid设备全局id
                HidD_GetHidGuid(ref hUSB);
                //取得一个包含所有HID接口信息集合的句柄
                IntPtr hidInfoSet = SetupDiGetClassDevs(ref hUSB, 0, IntPtr.Zero, DIGCF.DIGCF_PRESENT | DIGCF.DIGCF_DEVICEINTERFACE);
                if (hidInfoSet != IntPtr.Zero)
                {
                    SP_DEVICE_INTERFACE_DATA interfaceInfo = new SP_DEVICE_INTERFACE_DATA();
                    interfaceInfo.cbSize = Marshal.SizeOf(interfaceInfo);
                    //查询集合中每一个接口
                    for (index = 0; index < MAX_USB_DEVICES; index++)
                    {
                        //得到第index个接口信息
                        if (SetupDiEnumDeviceInterfaces(hidInfoSet, IntPtr.Zero, ref hUSB, index, ref interfaceInfo))
                        {
                            int buffsize = 0;
                            // 取得接口详细信息:第一次读取错误,但可以取得信息缓冲区的大小
                            SetupDiGetDeviceInterfaceDetail(hidInfoSet, ref interfaceInfo, IntPtr.Zero, buffsize, ref buffsize, null);
                            //构建接收缓冲
                            IntPtr pDetail = Marshal.AllocHGlobal(buffsize);
                            SP_DEVICE_INTERFACE_DETAIL_DATA detail = new SP_DEVICE_INTERFACE_DETAIL_DATA();
                            detail.cbSize = Marshal.SizeOf(typeof(SP_DEVICE_INTERFACE_DETAIL_DATA));
                            Marshal.StructureToPtr(detail, pDetail, false);
                            if (SetupDiGetDeviceInterfaceDetail(hidInfoSet, ref interfaceInfo, pDetail, buffsize, ref buffsize, null))
                            {
                                deviceList.Add(Marshal.PtrToStringAuto((IntPtr)((int)pDetail + 4)));
                            }
                            Marshal.FreeHGlobal(pDetail);
                        }
                    }
                }
                SetupDiDestroyDeviceInfoList(hidInfoSet);
                //return deviceList.ToArray();
            }
    
            #region<连接USB返回的结构体信息>
            /// <summary>
            /// 连接USB返回的结构体信息
            /// </summary>
            public enum HID_RETURN
            {
                SUCCESS = 0,
                NO_DEVICE_CONECTED,
                DEVICE_NOT_FIND,
                DEVICE_OPENED,
                WRITE_FAILD,
                READ_FAILD
    
            }
            #endregion
    
    
            // 以下是调用windows的API的函数
            /// <summary>
            /// The HidD_GetHidGuid routine returns the device interface GUID for HIDClass devices.
            /// </summary>
            /// <param name="HidGuid">a caller-allocated GUID buffer that the routine uses to return the device interface GUID for HIDClass devices.</param>
            [DllImport("hid.dll")]
            private static extern void HidD_GetHidGuid(ref Guid HidGuid);
    
            /// <summary>
            /// The SetupDiGetClassDevs function returns a handle to a device information set that contains requested device information elements for a local machine.
            /// </summary>
            /// <param name="ClassGuid">GUID for a device setup class or a device interface class. </param>
            /// <param name="Enumerator">A pointer to a NULL-terminated string that supplies the name of a PnP enumerator or a PnP device instance identifier. </param>
            /// <param name="HwndParent">A handle of the top-level window to be used for a user interface</param>
            /// <param name="Flags">A variable  that specifies control options that filter the device information elements that are added to the device information set. </param>
            /// <returns>a handle to a device information set </returns>
            [DllImport("setupapi.dll", SetLastError = true)]
            private static extern IntPtr SetupDiGetClassDevs(ref Guid ClassGuid, uint Enumerator, IntPtr HwndParent, DIGCF Flags);
    
            /// <summary>
            /// The SetupDiDestroyDeviceInfoList function deletes a device information set and frees all associated memory.
            /// </summary>
            /// <param name="DeviceInfoSet">A handle to the device information set to delete.</param>
            /// <returns>returns TRUE if it is successful. Otherwise, it returns FALSE </returns>
            [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
            private static extern Boolean SetupDiDestroyDeviceInfoList(IntPtr deviceInfoSet);
    
            /// <summary>
            /// The SetupDiEnumDeviceInterfaces function enumerates the device interfaces that are contained in a device information set.
            /// </summary>
            /// <param name="deviceInfoSet">A pointer to a device information set that contains the device interfaces for which to return information</param>
            /// <param name="deviceInfoData">A pointer to an SP_DEVINFO_DATA structure that specifies a device information element in DeviceInfoSet</param>
            /// <param name="interfaceClassGuid">a GUID that specifies the device interface class for the requested interface</param>
            /// <param name="memberIndex">A zero-based index into the list of interfaces in the device information set</param>
            /// <param name="deviceInterfaceData">a caller-allocated buffer that contains a completed SP_DEVICE_INTERFACE_DATA structure that identifies an interface that meets the search parameters</param>
            /// <returns></returns>
            [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
            private static extern Boolean SetupDiEnumDeviceInterfaces(IntPtr deviceInfoSet, IntPtr deviceInfoData, ref Guid interfaceClassGuid, UInt32 memberIndex, ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData);
    
            /// <summary>
            /// The SetupDiGetDeviceInterfaceDetail function returns details about a device interface.
            /// </summary>
            /// <param name="deviceInfoSet">A pointer to the device information set that contains the interface for which to retrieve details</param>
            /// <param name="deviceInterfaceData">A pointer to an SP_DEVICE_INTERFACE_DATA structure that specifies the interface in DeviceInfoSet for which to retrieve details</param>
            /// <param name="deviceInterfaceDetailData">A pointer to an SP_DEVICE_INTERFACE_DETAIL_DATA structure to receive information about the specified interface</param>
            /// <param name="deviceInterfaceDetailDataSize">The size of the DeviceInterfaceDetailData buffer</param>
            /// <param name="requiredSize">A pointer to a variable that receives the required size of the DeviceInterfaceDetailData buffer</param>
            /// <param name="deviceInfoData">A pointer buffer to receive information about the device that supports the requested interface</param>
            /// <returns></returns>
            [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
            private static extern bool SetupDiGetDeviceInterfaceDetail(IntPtr deviceInfoSet, ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData, IntPtr deviceInterfaceDetailData, int deviceInterfaceDetailDataSize, ref int requiredSize, SP_DEVINFO_DATA deviceInfoData);
    
            /// <summary>
            /// The HidD_GetAttributes routine returns the attributes of a specified top-level collection.
            /// </summary>
            /// <param name="HidDeviceObject">Specifies an open handle to a top-level collection</param>
            /// <param name="Attributes">a caller-allocated HIDD_ATTRIBUTES structure that returns the attributes of the collection specified by HidDeviceObject</param>
            /// <returns></returns>
            [DllImport("hid.dll")]
            private static extern Boolean HidD_GetAttributes(IntPtr hidDeviceObject, out HIDD_ATTRIBUTES attributes);
            /// <summary>
            /// The HidD_GetSerialNumberString routine returns the embedded string of a top-level collection that identifies the serial number of the collection's physical device.
            /// </summary>
            /// <param name="HidDeviceObject">Specifies an open handle to a top-level collection</param>
            /// <param name="Buffer">a caller-allocated buffer that the routine uses to return the requested serial number string</param>
            /// <param name="BufferLength">Specifies the length, in bytes, of a caller-allocated buffer provided at Buffer</param>
            /// <returns></returns>
            [DllImport("hid.dll")]
            private static extern Boolean HidD_GetSerialNumberString(IntPtr hidDeviceObject, IntPtr buffer, int bufferLength);
    
            /// <summary>
            /// The HidD_GetPreparsedData routine returns a top-level collection's preparsed data.
            /// </summary>
            /// <param name="hidDeviceObject">Specifies an open handle to a top-level collection. </param>
            /// <param name="PreparsedData">Pointer to the address of a routine-allocated buffer that contains a collection's preparsed data in a _HIDP_PREPARSED_DATA structure.</param>
            /// <returns>HidD_GetPreparsedData returns TRUE if it succeeds; otherwise, it returns FALSE.</returns>
            [DllImport("hid.dll")]
            private static extern Boolean HidD_GetPreparsedData(IntPtr hidDeviceObject, out IntPtr PreparsedData);
    
            [DllImport("hid.dll")]
            private static extern Boolean HidD_FreePreparsedData(IntPtr PreparsedData);
    
            [DllImport("hid.dll")]
            private static extern uint HidP_GetCaps(IntPtr PreparsedData, out HIDP_CAPS Capabilities);
    
    
            /// <summary>
            /// This function creates, opens, or truncates a file, COM port, device, service, or console.
            /// </summary>
            /// <param name="fileName">a null-terminated string that specifies the name of the object</param>
            /// <param name="desiredAccess">Type of access to the object</param>
            /// <param name="shareMode">Share mode for object</param>
            /// <param name="securityAttributes">Ignored; set to NULL</param>
            /// <param name="creationDisposition">Action to take on files that exist, and which action to take when files do not exist</param>
            /// <param name="flagsAndAttributes">File attributes and flags for the file</param>
            /// <param name="templateFile">Ignored</param>
            /// <returns>An open handle to the specified file indicates success</returns>
            [DllImport("kernel32.dll", SetLastError = true)]
            private static extern IntPtr CreateFile(string fileName, uint desiredAccess, uint shareMode, uint securityAttributes, uint creationDisposition, uint flagsAndAttributes, uint templateFile);
    
            /// <summary>
            /// This function closes an open object handle.
            /// </summary>
            /// <param name="hObject">Handle to an open object</param>
            /// <returns></returns>
            [DllImport("kernel32.dll")]
            private static extern int CloseHandle(IntPtr hObject);
    
            /// <summary>
            /// This function reads data from a file, starting at the position indicated by the file pointer.
            /// </summary>
            /// <param name="file">Handle to the file to be read</param>
            /// <param name="buffer">Pointer to the buffer that receives the data read from the file </param>
            /// <param name="numberOfBytesToRead">Number of bytes to be read from the file</param>
            /// <param name="numberOfBytesRead">Pointer to the number of bytes read</param>
            /// <param name="lpOverlapped">Unsupported; set to NULL</param>
            /// <returns></returns>
            [DllImport("Kernel32.dll", SetLastError = true)]
            private static extern bool ReadFile(IntPtr file, byte[] buffer, uint numberOfBytesToRead, out uint numberOfBytesRead, IntPtr lpOverlapped);
    
            /// <summary>
            ///  This function writes data to a file
            /// </summary>
            /// <param name="file">Handle to the file to be written to</param>
            /// <param name="buffer">Pointer to the buffer containing the data to write to the file</param>
            /// <param name="numberOfBytesToWrite">Number of bytes to write to the file</param>
            /// <param name="numberOfBytesWritten">Pointer to the number of bytes written by this function call</param>
            /// <param name="lpOverlapped">Unsupported; set to NULL</param>
            /// <returns></returns>
            [DllImport("Kernel32.dll", SetLastError = true)]
            private static extern bool WriteFile(IntPtr file, byte[] buffer, uint numberOfBytesToWrite, out uint numberOfBytesWritten, IntPtr lpOverlapped);
    
            /// <summary>
            /// Registers the device or type of device for which a window will receive notifications
            /// </summary>
            /// <param name="recipient">A handle to the window or service that will receive device events for the devices specified in the NotificationFilter parameter</param>
            /// <param name="notificationFilter">A pointer to a block of data that specifies the type of device for which notifications should be sent</param>
            /// <param name="flags">A Flags that specify the handle type</param>
            /// <returns>If the function succeeds, the return value is a device notification handle</returns>
            [DllImport("User32.dll", SetLastError = true)]
            private static extern IntPtr RegisterDeviceNotification(IntPtr recipient, IntPtr notificationFilter, int flags);
    
            /// <summary>
            /// Closes the specified device notification handle.
            /// </summary>
            /// <param name="handle">Device notification handle returned by the RegisterDeviceNotification function</param>
            /// <returns></returns>
            [DllImport("user32.dll", SetLastError = true)]
            private static extern bool UnregisterDeviceNotification(IntPtr handle);
        }
        #region
        /// <summary>
        /// SP_DEVICE_INTERFACE_DATA structure defines a device interface in a device information set.
        /// </summary>
        public struct SP_DEVICE_INTERFACE_DATA
        {
            public int cbSize;
            public Guid interfaceClassGuid;
            public int flags;
            public int reserved;
        }
    
        /// <summary>
        /// SP_DEVICE_INTERFACE_DETAIL_DATA structure contains the path for a device interface.
        /// </summary>
        [StructLayout(LayoutKind.Sequential, Pack = 2)]
        internal struct SP_DEVICE_INTERFACE_DETAIL_DATA
        {
            internal int cbSize;
            internal short devicePath;
        }
    
        /// <summary>
        /// SP_DEVINFO_DATA structure defines a device instance that is a member of a device information set.
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public class SP_DEVINFO_DATA
        {
            public int cbSize = Marshal.SizeOf(typeof(SP_DEVINFO_DATA));
            public Guid classGuid = Guid.Empty; // temp
            public int devInst = 0; // dumy
            public int reserved = 0;
        }
        /// <summary>
        /// Flags controlling what is included in the device information set built by SetupDiGetClassDevs
        /// </summary>
        public enum DIGCF
        {
            DIGCF_DEFAULT = 0x00000001, // only valid with DIGCF_DEVICEINTERFACE
            DIGCF_PRESENT = 0x00000002,
            DIGCF_ALLCLASSES = 0x00000004,
            DIGCF_PROFILE = 0x00000008,
            DIGCF_DEVICEINTERFACE = 0x00000010
        }
        /// <summary>
        /// The HIDD_ATTRIBUTES structure contains vendor information about a HIDClass device
        /// </summary>
        public struct HIDD_ATTRIBUTES
        {
            public int Size;
            public ushort VendorID;
            public ushort ProductID;
            public ushort VersionNumber;
        }
    
        public struct HIDP_CAPS
        {
            public ushort Usage;
            public ushort UsagePage;
            public ushort InputReportByteLength;
            public ushort OutputReportByteLength;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)]
            public ushort[] Reserved;
            public ushort NumberLinkCollectionNodes;
            public ushort NumberInputButtonCaps;
            public ushort NumberInputValueCaps;
            public ushort NumberInputDataIndices;
            public ushort NumberOutputButtonCaps;
            public ushort NumberOutputValueCaps;
            public ushort NumberOutputDataIndices;
            public ushort NumberFeatureButtonCaps;
            public ushort NumberFeatureValueCaps;
            public ushort NumberFeatureDataIndices;
        }
        /// <summary>
        /// Type of access to the object.
        ///</summary>
        static class DESIREDACCESS
        {
            public const uint GENERIC_READ = 0x80000000;
            public const uint GENERIC_WRITE = 0x40000000;
            public const uint GENERIC_EXECUTE = 0x20000000;
            public const uint GENERIC_ALL = 0x10000000;
        }
        /// <summary>
        /// Action to take on files that exist, and which action to take when files do not exist.
        /// </summary>
        static class CREATIONDISPOSITION
        {
            public const uint CREATE_NEW = 1;
            public const uint CREATE_ALWAYS = 2;
            public const uint OPEN_EXISTING = 3;
            public const uint OPEN_ALWAYS = 4;
            public const uint TRUNCATE_EXISTING = 5;
        }
        /// <summary>
        /// File attributes and flags for the file.
        /// </summary>
        static class FLAGSANDATTRIBUTES
        {
            public const uint FILE_FLAG_WRITE_THROUGH = 0x80000000;
            public const uint FILE_FLAG_OVERLAPPED = 0x40000000;
            public const uint FILE_FLAG_NO_BUFFERING = 0x20000000;
            public const uint FILE_FLAG_RANDOM_ACCESS = 0x10000000;
            public const uint FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000;
            public const uint FILE_FLAG_DELETE_ON_CLOSE = 0x04000000;
            public const uint FILE_FLAG_BACKUP_SEMANTICS = 0x02000000;
            public const uint FILE_FLAG_POSIX_SEMANTICS = 0x01000000;
            public const uint FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000;
            public const uint FILE_FLAG_OPEN_NO_RECALL = 0x00100000;
            public const uint FILE_FLAG_FIRST_PIPE_INSTANCE = 0x00080000;
        }
        /// <summary>
        /// Serves as a standard header for information related to a device event reported through the WM_DEVICECHANGE message.
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct DEV_BROADCAST_HDR
        {
            public int dbcc_size;
            public int dbcc_devicetype;
            public int dbcc_reserved;
        }
        /// <summary>
        /// Contains information about a class of devices
        /// </summary>
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
        public struct DEV_BROADCAST_DEVICEINTERFACE
        {
            public int dbcc_size;
            public int dbcc_devicetype;
            public int dbcc_reserved;
            public Guid dbcc_classguid;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 255)]
            public string dbcc_name;
        }
        #endregion
    }

    HIDInterface.cs

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.IO;
    using System.Text;
    using System.Threading;
    using System.Windows.Forms;
    
    namespace HID_SIMPLE.HID
    {
        public class HIDInterface : IDisposable
        {
    
            public enum MessagesType
            {
                Message,
                Error
            }
    
            public struct ReusltString
            {
                public bool Result;
                public string message;
            }
    
            public struct HidDevice
            {
                public UInt16 vID;
                public UInt16 pID;
                public string serial;
            }
            HidDevice lowHidDevice = new HidDevice();
    
            public delegate void DelegateDataReceived(object sender, byte[] data);
            public DelegateDataReceived DataReceived;
    
            public delegate void DelegateStatusConnected(object sender, bool isConnect);
            public DelegateStatusConnected StatusConnected;
    
            public bool bConnected = false;
    
    
            public Hid oSp = new Hid();
            private static HIDInterface m_oInstance;
    
            public struct TagInfo
            {
                public string AntennaPort;
                public string EPC;
            }
    
            public HIDInterface()
            {
                m_oInstance = this;
                oSp.DataReceived = HidDataReceived;
                oSp.DeviceRemoved = HidDeviceRemoved;
            }
    
            protected virtual void RaiseEventConnectedState(bool isConnect)
            {
                if (null != StatusConnected) StatusConnected(this, isConnect);
            }
    
            protected virtual void RaiseEventDataReceived(byte[] buf)
            {
                if(null != DataReceived) DataReceived(this, buf);
            }
    
            public void AutoConnect(HidDevice hidDevice)
            {
                lowHidDevice = hidDevice;
                ContinueConnectFlag = true;
                ReadWriteThread.DoWork += ReadWriteThread_DoWork;
                ReadWriteThread.WorkerSupportsCancellation = true;
                ReadWriteThread.RunWorkerAsync();    //Recommend performing USB read/write operations in a separate thread.  Otherwise,
            }
    
            public void StopAutoConnect()
            {
                try
                {
                    ContinueConnectFlag = false;
                    Dispose();
                }
                catch
                {
    
                }
            }
    
            ~HIDInterface()
            {
                Dispose();
            }
    
            public bool Connect(HidDevice hidDevice)
            {
                ReusltString result = new ReusltString();
    
                Hid.HID_RETURN hdrtn = oSp.OpenDevice(hidDevice.vID, hidDevice.pID, hidDevice.serial);
    
                if (hdrtn == Hid.HID_RETURN.SUCCESS)
                {
    
                    bConnected = true;
    
                    #region 消息通知
                    result.Result = true;
                    result.message = "Connect Success!";
                    RaiseEventConnectedState(result.Result);
                    #endregion
    
    
                    return true;
                }
    
                bConnected = false;
    
                #region 消息通知
                result.Result = false;
                result.message = "Device Connect Error";
                RaiseEventConnectedState(result.Result);
    
                #endregion
                return false;
            }
    
    
            public bool Send(byte[] byData)
            {
                byte[] sendtemp = new byte[byData.Length + 1];
                sendtemp[0] = (byte)byData.Length;
                Array.Copy(byData, 0, sendtemp, 1, byData.Length);
    
                Hid.HID_RETURN hdrtn = oSp.Write(new report(0, sendtemp));
    
                if (hdrtn != Hid.HID_RETURN.SUCCESS)
                {
                    return false;
                }
                return true;
            }
    
            public bool Send(string strData)
            {
                //获得报文的编码字节
                byte[] data = Encoding.Unicode.GetBytes(strData);
                return Send(data);
            }
    
    
    
            public void DisConnect()
            {
                bConnected = false;
    
                Thread.Sleep(200);
                if (oSp != null)
                {
                    oSp.CloseDevice();
                }
            }
    
    
            void HidDeviceRemoved(object sender, EventArgs e)
            {
                bConnected = false;
                #region 消息通知
                ReusltString result = new ReusltString();
                result.Result = false;
                result.message = "Device Remove";
                RaiseEventConnectedState(result.Result);
                #endregion
                if (oSp != null)
                {
                    oSp.CloseDevice();
                }
    
            }
    
            public void HidDataReceived(object sender, report e)
            {
    
                try
                {
                    //第一个字节为数据长度,因为Device 的HID数据固定长度为64字节,取有效数据
                    byte[] buf = new byte[e.reportBuff[0]];
                    Array.Copy(e.reportBuff, 1, buf, 0, e.reportBuff[0]);
    
                    //推送数据
                    RaiseEventDataReceived(buf);
                }
                catch
                {
                    #region 消息通知
                    ReusltString result = new ReusltString();
                    result.Result = false;
                    result.message = "Receive Error";
                    RaiseEventConnectedState(result.Result);
                    #endregion
                }
    
            }
    
            public void Dispose()
            {
                try
                {
                    this.DisConnect();
                    oSp.DataReceived -= HidDataReceived;
                    oSp.DeviceRemoved -= HidDeviceRemoved;
                    ReadWriteThread.DoWork -= ReadWriteThread_DoWork;
                    ReadWriteThread.CancelAsync();
                    ReadWriteThread.Dispose();
                }
                catch
                { }
            }
    
            Boolean ContinueConnectFlag = true;
            private BackgroundWorker ReadWriteThread = new BackgroundWorker();
            private void ReadWriteThread_DoWork(object sender, DoWorkEventArgs e)
            {
                while (ContinueConnectFlag)
                {
                    try
                    {
                        if (!bConnected)
                        {
                            Connect(lowHidDevice);
    
                        }
                        Thread.Sleep(500);
                    }
                    catch { }
                }
            }
    
        }
    }

    调用如下:

    #region parameter Define
    HIDInterface hid = new HIDInterface();
    
    
    struct connectStatusStruct
    {
        public bool preStatus;
        public bool curStatus;
    }
    
    connectStatusStruct connectStatus = new connectStatusStruct();
    
    //推送连接状态信息
    public delegate void isConnectedDelegate(bool isConnected);
    public isConnectedDelegate isConnectedFunc;
    
    
    //推送接收数据信息
    public delegate void PushReceiveDataDele(byte[] datas);
    public PushReceiveDataDele pushReceiveData;
    
    #endregion
    
    //第一步需要初始化,传入vid、pid,并开启自动连接
    public void Initial()
    {
    
        hid.StatusConnected = StatusConnected;
        hid.DataReceived = DataReceived;
    
        HIDInterface.HidDevice hidDevice = new HIDInterface.HidDevice();
        hidDevice.vID =0x04D8;
        hidDevice.pID = 0x003F;
        hidDevice.serial = "";
        hid.AutoConnect(hidDevice);
    
    }
    
    //不使用则关闭
    public void Close()
    {
        hid.StopAutoConnect();
    }
    
    //发送数据
    public bool SendBytes(byte[] data)
    {
    
        return hid.Send(data);
    
    }
    
    //接受到数据
    public void DataReceived(object sender, byte[] e)
    {
        if (pushReceiveData != null)
            pushReceiveData(e);
    }
    
    //状态改变接收
    public void StatusConnected(object sender, bool isConnect)
    {
        connectStatus.curStatus = isConnect;
        if (connectStatus.curStatus == connectStatus.preStatus)  //connect
            return;
        connectStatus.preStatus = connectStatus.curStatus;
    
        if(connectStatus.curStatus)
        {
            isConnectedFunc(true);
            //ReportMessage(MessagesType.Message, "连接成功");
        }
        else //disconnect
        {
            isConnectedFunc(false);
            //ReportMessage(MessagesType.Error, "无法连接");
        }
    }

    源码下载:

    https://github.com/mikeobrien/HidLibrary

  • 相关阅读:
    thinkphp3.2.3版本在windows本地apache环境运行正常,上传到centos服务器apache环境中出现:thinkphp 上传根目录不存在!请尝试手动创建:uploads/
    [POI2013]LUK-Triumphal arch
    【背包问题】
    2016 acm香港网络赛 A题. A+B Problem (FFT)
    tomcat部署项目的三种方式
    仿照ArrayList自己生成的MyList对象
    使用回调函数实现回文判断
    关于angularjs的model的一些问题
    关于使用Tomcat服务器出现413错误的解决办法(Request Entity Too Large)
    关于angularjs+typeahead的整合
  • 原文地址:https://www.cnblogs.com/zoro-zero/p/14960148.html
Copyright © 2011-2022 走看看