当前位置:
首页 > 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设备文件名
栏目列表
最新更新
nodejs爬虫
Python正则表达式完全指南
爬取豆瓣Top250图书数据
shp 地图文件批量添加字段
爬虫小试牛刀(爬取学校通知公告)
【python基础】函数-初识函数
【python基础】函数-返回值
HTTP请求:requests模块基础使用必知必会
Python初学者友好丨详解参数传递类型
如何有效管理爬虫流量?
SQL SERVER中递归
2个场景实例讲解GaussDB(DWS)基表统计信息估
常用的 SQL Server 关键字及其含义
动手分析SQL Server中的事务中使用的锁
openGauss内核分析:SQL by pass & 经典执行
一招教你如何高效批量导入与更新数据
天天写SQL,这些神奇的特性你知道吗?
openGauss内核分析:执行计划生成
[IM002]Navicat ODBC驱动器管理器 未发现数据
初入Sql Server 之 存储过程的简单使用
这是目前我见过最好的跨域解决方案!
减少回流与重绘
减少回流与重绘
如何使用KrpanoToolJS在浏览器切图
performance.now() 与 Date.now() 对比
一款纯 JS 实现的轻量化图片编辑器
关于开发 VS Code 插件遇到的 workbench.scm.
前端设计模式——观察者模式
前端设计模式——中介者模式
创建型-原型模式