一、简叙
写工控上位机的搬砖人,难免会遇到USB通讯,在一个项目中,我写的上位机使用USB HID协议和STM32通讯传输数据,从零大概花了几天找例程,找资料,最后是各种搬砖修补,终于出来了一个出版DOME,能和下位机实时通讯了。
HID通讯方式其实很常见,像鼠标、键盘等待外设都是这种方式,我也不知道为啥要用这种方式,我当初用它是因为其传输速率比串口快(忆当初下位机还没开发出网口的苦日子),再则其是免驱(win内置驱动,直接调API即可)。
HID识别设备主要通过设备的PID(厂商ID)和VID(产品ID),进而区分。
二、主体程序
网上找了很多版本,主体程序都是大同小异,最后我便借鉴了一篇博文,来砌我的主体程序。
很不出意外,砌出来的东西不行。记得以前听前辈说过一句话,你的薪资多高取决于你填坑的能力有多强。
现在想想确实如此,在这个互联网的时代,搬砖并不是一件难事,但是不能确保搬来的砖不是每一块都适合你,你必须要修修补补再用,所以修补的能力便成了你赚钱的能力。
还有我奉献各位年轻气旺年轻人,不要急于求成,网上找到源码不是难事,必须一步一个脚印,把源码啃了,不要以为会搬砖就老子天下第一,那有多难的事呀。(没错,我以前包括现在都是这么一个烂人,正努力扭正态度)。
我们不重复造车轮,但我们必须有造车轮的能力,出来混,迟早要跪的。
下面我贴上我的主要源码部分,基本和其他博文的一样:
namespace HID { #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; } static class DEVICE_FLAG { /// <summary>Windows message sent when a device is inserted or removed</summary> public const int WM_DEVICECHANGE = 0x0219; /// <summary>WParam for above : A device was inserted</summary> public const int DEVICE_ARRIVAL = 0x8000; /// <summary>WParam for above : A device was removed</summary> public const int DEVICE_REMOVECOMPLETE = 0x8004; /// <summary>Used when registering for device insert/remove messages : specifies the type of device</summary> public const int DEVTYP_DEVICEINTERFACE = 0x05; /// <summary>Used when registering for device insert/remove messages : we\'re giving the API call a window handle</summary> public const int DEVICE_NOTIFY_WINDOW_HANDLE = 0; } /// <summary> /// Sharing mode of the file or object ///</summary> static class SHAREMODE { public const uint FILE_SHARE_READ = 0x00000001; public const uint FILE_SHARE_WRITE = 0x00000002; public const uint FILE_SHARE_DELETE = 0x00000004; } #endregion /// <summary> /// 传入ID和arraybuff(只读) /// </summary> 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 { #region 声明winAPI // **************************以下是调用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", CharSet = CharSet.Auto, 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 = false)] private static extern Boolean SetupDiEnumDeviceInterfaces(IntPtr deviceInfoSet, IntPtr deviceInfoData, ref Guid interfaceClassGuid, uint 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 = false, 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 = false)] 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 = false)] 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 = false)] 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 = false)] 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 = false)] private static extern bool UnregisterDeviceNotification(IntPtr handle); #endregion #region 定义字段/属性 public UInt16 VID = 0x0483; public UInt16 PID = 0x5750
请发表评论