VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > Python基础教程 >
  • C#教程之C# 连蒙带骗不知所以然的搞定USB下位机读

公司用了一台发卡机,usb接口,半双工,给了个dll,不支持线程操作,使得UI线程老卡。

懊恼了,想自己直接通过usb读写,各种百度,然后是无数的坑,最终搞定。

现将各种坑和我自己的某些猜想记录一下,也供各位参考。

一、常量定义

1
2
3
4
5
6
7
8
9
10
private const short INVALID_HANDLE_VALUE = -1;
private const uint GENERIC_READ = 0x80000000;
private const uint GENERIC_WRITE = 0x40000000;
private const uint FILE_SHARE_READ = 0x00000001;
private const uint FILE_SHARE_WRITE = 0x00000002;
private const uint CREATE_NEW = 1;
private const uint CREATE_ALWAYS = 2;
private const uint OPEN_EXISTING = 3;
private const uint FILE_FLAG_OVERLAPPED = 0x40000000;
private const uint FILE_ATTRIBUTE_NORMAL = 0x00000080;

主要用于CreateFile时用。

 

二、结构、枚举、类定义

复制代码
        private struct HID_ATTRIBUTES
        {
            public int Size;
            public ushort VendorID;
            public ushort ProductID;
            public ushort VersionNumber;
        }
        private struct SP_DEVICE_INTERFACE_DATA
        {
            public int cbSize;
            public Guid interfaceClassGuid;
            public int flags;
            public int reserved;
        }
        [StructLayout(LayoutKind.Sequential)]
        private class SP_DEVINFO_DATA
        {
            public int cbSize = Marshal.SizeOf<SP_DEVINFO_DATA>();
            public Guid classGuid = Guid.Empty;
            public int devInst = 0;
            public int reserved = 0;
        }
        [StructLayout(LayoutKind.Sequential, Pack = 2)]
        private struct SP_DEVICE_INTERFACE_DETAIL_DATA
        {
            internal int cbSize;
            internal short devicePath;
        }
        private enum DIGCF
        {
            DIGCF_DEFAULT = 0x1,
            DIGCF_PRESENT = 0x2,
            DIGCF_ALLCLASSES = 0x4,
            DIGCF_PROFILE = 0x8,
            DIGCF_DEVICEINTERFACE = 0x10
        }
        [StructLayout(LayoutKind.Sequential)]
        private struct HIDP_CAPS
        {
            /// <summary>
            /// Specifies a top-level collection's usage ID.
            /// </summary>
            public System.UInt16 Usage;
            /// <summary>
            /// Specifies the top-level collection's usage page.
            /// </summary>
            public System.UInt16 UsagePage;
            /// <summary>
            /// 输入报告的最大节数数量(如果使用报告ID,则包含报告ID的字节)
            /// Specifies the maximum size, in bytes, of all the input reports (including the report ID, if report IDs are used, which is prepended to the report data).
            /// </summary>
            public System.UInt16 InputReportByteLength;
            /// <summary>
            /// Specifies the maximum size, in bytes, of all the output reports (including the report ID, if report IDs are used, which is prepended to the report data).
            /// </summary>
            public System.UInt16 OutputReportByteLength;
            /// <summary>
            /// Specifies the maximum length, in bytes, of all the feature reports (including the report ID, if report IDs are used, which is prepended to the report data).
            /// </summary>
            public System.UInt16 FeatureReportByteLength;
            /// <summary>
            /// Reserved for internal system use.
            /// </summary>
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)]
            public System.UInt16[] Reserved;
            /// <summary>
            /// pecifies the number of HIDP_LINK_COLLECTION_NODE structures that are returned for this top-level collection by HidP_GetLinkCollectionNodes.
            /// </summary>
            public System.UInt16 NumberLinkCollectionNodes;
            /// <summary>
            /// Specifies the number of input HIDP_BUTTON_CAPS structures that HidP_GetButtonCaps returns.
            /// </summary>
            public System.UInt16 NumberInputButtonCaps;
            /// <summary>
            /// Specifies the number of input HIDP_VALUE_CAPS structures that HidP_GetValueCaps returns.
            /// </summary>
            public System.UInt16 NumberInputValueCaps;
            /// <summary>
            /// Specifies the number of data indices assigned to buttons and values in all input reports.
            /// </summary>
            public System.UInt16 NumberInputDataIndices;
            /// <summary>
            /// Specifies the number of output HIDP_BUTTON_CAPS structures that HidP_GetButtonCaps returns.
            /// </summary>
            public System.UInt16 NumberOutputButtonCaps;
            /// <summary>
            /// Specifies the number of output HIDP_VALUE_CAPS structures that HidP_GetValueCaps returns.
            /// </summary>
            public System.UInt16 NumberOutputValueCaps;
            /// <summary>
            /// Specifies the number of data indices assigned to buttons and values in all output reports.
            /// </summary>
            public System.UInt16 NumberOutputDataIndices;
            /// <summary>
            /// Specifies the total number of feature HIDP_BUTTONS_CAPS structures that HidP_GetButtonCaps returns.
            /// </summary>
            public System.UInt16 NumberFeatureButtonCaps;
            /// <summary>
            /// Specifies the total number of feature HIDP_VALUE_CAPS structures that HidP_GetValueCaps returns.
            /// </summary>
            public System.UInt16 NumberFeatureValueCaps;
            /// <summary>
            /// Specifies the number of data indices assigned to buttons and values in all feature reports.
            /// </summary>
            public System.UInt16 NumberFeatureDataIndices;
        }
复制代码

都是从各种地方复制过来的。最后的结构注释从微软那里复制了英文,翻译了一句中文。因为这个坑最大。

三、Dll封装

复制代码
        /// <summary>
        /// 过滤设备,获取需要的设备
        /// </summary>
        /// <param name="ClassGuid"></param>
        /// <param name="Enumerator"></param>
        /// <param name="HwndParent"></param>
        /// <param name="Flags"></param>
        /// <returns></returns>
        [DllImport("setupapi.dll", SetLastError = true)]
        private static extern IntPtr SetupDiGetClassDevs(ref Guid ClassGuid, uint Enumerator, IntPtr HwndParent, DIGCF Flags);
        /// <summary>
        /// 获取设备,true获取到
        /// </summary>
        /// <param name="hDevInfo"></param>
        /// <param name="devInfo"></param>
        /// <param name="interfaceClassGuid"></param>
        /// <param name="memberIndex"></param>
        /// <param name="deviceInterfaceData"></param>
        /// <returns></returns>
        [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern Boolean SetupDiEnumDeviceInterfaces(IntPtr hDevInfo, IntPtr devInfo, ref Guid interfaceClassGuid, UInt32 memberIndex, ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData);
        /// <summary>
        /// 获取接口的详细信息 必须调用两次 第1次返回长度 第2次获取数据
        /// </summary>
        /// <param name="deviceInfoSet"></param>
        /// <param name="deviceInterfaceData"></param>
        /// <param name="deviceInterfaceDetailData"></param>
        /// <param name="deviceInterfaceDetailDataSize"></param>
        /// <param name="requiredSize"></param>
        /// <param name="deviceInfoData"></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>
        /// 删除设备信息并释放内存
        /// </summary>
        /// <param name="HIDInfoSet"></param>
        /// <returns></returns>
        [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern Boolean SetupDiDestroyDeviceInfoList(IntPtr HIDInfoSet);


        /// <summary>
        /// 获取设备文件
        /// </summary>
        /// <param name="lpFileName"></param>
        /// <param name="dwDesiredAccess">access mode</param>
        /// <param name="dwShareMode">share mode</param>
        /// <param name="lpSecurityAttributes">SD</param>
        /// <param name="dwCreationDisposition">how to create</param>
        /// <param name="dwFlagsAndAttributes">file attributes</param>
        /// <param name="hTemplateFile">handle to template file</param>
        /// <returns></returns>
        [DllImport("kernel32.dll", SetLastError = true)]
        private static extern IntPtr CreateFile(string lpFileName, uint dwDesiredAccess, uint dwShareMode, uint lpSecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, uint hTemplateFile);
        [DllImport("kernel32.dll", SetLastError = true)]
        [return: System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)]
        private static extern bool WriteFile(System.IntPtr hFile, byte[] lpBuffer, uint nNumberOfBytesToWrite, out uint lpNumberOfBytesWritten, IntPtr lpOverlapped);
        [DllImport("kernel32.dll", SetLastError = true)]
        private static extern int CloseHandle(int hObject);

        /// <summary>
        /// 获得GUID
        /// </summary>
        /// <param name="HidGuid"></param>
        [DllImport("hid.dll")]
        private static extern void HidD_GetHidGuid(ref Guid HidGuid);
        [DllImport("hid.dll")]
        private static extern Boolean HidD_GetPreparsedData(IntPtr hidDeviceObject, out IntPtr PreparsedData);
        [DllImport("hid.dll")]
        private static extern uint HidP_GetCaps(IntPtr PreparsedData, out HIDP_CAPS Capabilities);
        [DllImport("hid.dll")]
        private static extern Boolean HidD_FreePreparsedData(IntPtr PreparsedData);
        [DllImport("hid.dll")]
        private static extern Boolean HidD_GetAttributes(IntPtr hidDevice, out HID_ATTRIBUTES attributes);
复制代码

 

四、几个属性

        private int _InputBufferSize;
        private int _OutputBufferSize;
        private FileStream _UsbFileStream = null;

五、几个方法

Usb设备的读写跟磁盘文件的读写没区别,需要打开文件、读文件、写文件,最后关闭文件。

磁盘文件大家都清楚,比如“c:\data\hello.txt”就是个文件名,前面加“\\计算机A”则是其他计算机上的某文件名,Usb设备也有文件名,如我的设备的文件名就是“\\?\hid#vid_5131&pid_2007#7&252e9bc9&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}”。

哪弄来的?头大了吧,我也头大,什么鬼?百度了,未果,所以干脆不管了。先来一个列出全部Usb设备文件名的方法

(一)获取所有Usb设备文件名