C# 访问USB(HID)设备-阿里云开发者社区

开发者社区> 杰克.陈> 正文

C# 访问USB(HID)设备

简介: 原文:C# 访问USB(HID)设备 二话不说,直接给代码,如果您真想做这方面的东西,还是稍微研究下,没有现成的好类用,就需要自己了解其原理 //引用空间using System;using System.
+关注继续查看
原文:C# 访问USB(HID)设备

二话不说,直接给代码,如果您真想做这方面的东西,还是稍微研究下,没有现成的好类用,就需要自己了解其原理

//引用空间
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Threading;
using System.Collections;
using System.IO;

 //以下是调用windows的API的函数
        
//获得GUID
        [DllImport("hid.dll")]
        public static extern void HidD_GetHidGuid(ref Guid HidGuid);
        Guid guidHID = Guid.Empty;
        //过滤设备,获取需要的设备
        [DllImport("setupapi.dll", SetLastError = true)]
        public static extern IntPtr SetupDiGetClassDevs(ref Guid ClassGuid, uint Enumerator, IntPtr HwndParent, DIGCF Flags);
        IntPtr hDevInfo;
        //获取设备,true获取到
        [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern Boolean SetupDiEnumDeviceInterfaces(IntPtr hDevInfo, IntPtr devInfo, ref Guid interfaceClassGuid, UInt32 memberIndex, ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData);
        public struct SP_DEVICE_INTERFACE_DATA
        {
            public int cbSize ;
            public Guid interfaceClassGuid;
            public int flags;
            public int reserved;
        }

        // 获取接口的详细信息 必须调用两次 第1次返回长度 第2次获取数据 
        [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);
        [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;
        }

        [StructLayout(LayoutKind.Sequential, Pack = 2)]
        internal struct SP_DEVICE_INTERFACE_DETAIL_DATA
        {
            internal int cbSize;
            internal short devicePath;
        }

        public enum DIGCF
        {
            DIGCF_DEFAULT = 0x1,
            DIGCF_PRESENT = 0x2,
            DIGCF_ALLCLASSES = 0x4,
            DIGCF_PROFILE = 0x8,
            DIGCF_DEVICEINTERFACE = 0x10
        }

        //获取设备文件
        [DllImport("kernel32.dll", SetLastError = true)]
        private static extern int CreateFile(
            string lpFileName,                            // file name
            uint dwDesiredAccess,                        // access mode
            uint dwShareMode,                            // share mode
            uint lpSecurityAttributes,                    // SD
            uint dwCreationDisposition,                    // how to create
            uint dwFlagsAndAttributes,                    // file attributes
            uint hTemplateFile                            // handle to template file
            );
        //读取设备文件
        [DllImport("Kernel32.dll",SetLastError = true)]
        private static extern bool ReadFile
            (
                IntPtr hFile,
                byte[] lpBuffer,
                uint nNumberOfBytesToRead,
                ref uint lpNumberOfBytesRead,
                IntPtr lpOverlapped
            );

        //释放设备
        [DllImport("hid.dll")]
        static public extern bool HidD_FreePreparsedData(ref IntPtr PreparsedData);
        //关闭访问设备句柄,结束进程的时候把这个加上保险点
        [DllImport("kernel32.dll")]
        static public extern int CloseHandle(int hObject);

接下来是访问设备的代码

//代码暂时没有整理,传入参数是设备序号,
//有些USB设备其实有很多HID设备,就是一个接口上有几个设备,这个时候需要
//用index++来逐个循环,直到获取设备返回false后,跳出去,把获取的设备
//路径全记录下来就好了,我这里知道具体设备号,所以没有循环,浪费我时间

         
//定于句柄序号和一些参数,具体可以去网上找这些API的参数说明,后文我看能不能把资料也写上去
         int HidHandle = -1;
        public const uint GENERIC_READ = 0x80000000;
        public const uint GENERIC_WRITE = 0x40000000;
        public const uint FILE_SHARE_READ= 0x00000001;
        public const uint FILE_SHARE_WRITE = 0x00000002;
        public const int OPEN_EXISTING = 3;

private void UsBMethod(int index)
        {
            HidD_GetHidGuid(ref guidHID);
            hDevInfo = SetupDiGetClassDevs(ref guidHID, 0, IntPtr.Zero, DIGCF.DIGCF_PRESENT | DIGCF.DIGCF_DEVICEINTERFACE);
            int bufferSize = 0;
            ArrayList HIDUSBAddress = new ArrayList();

            //while (true)
            
//{
            
//获取设备,true获取到
             SP_DEVICE_INTERFACE_DATA DeviceInterfaceData = new SP_DEVICE_INTERFACE_DATA();
            DeviceInterfaceData.cbSize = Marshal.SizeOf(DeviceInterfaceData);
            //for (int i = 0; i < 3; i++)
            
//{
                bool result = SetupDiEnumDeviceInterfaces(hDevInfo, IntPtr.Zero, ref guidHID, (UInt32)index, ref DeviceInterfaceData);
            //}
            
//第一次调用出错,但可以返回正确的Size 
            SP_DEVINFO_DATA strtInterfaceData = new SP_DEVINFO_DATA();
            result = SetupDiGetDeviceInterfaceDetail(hDevInfo, ref DeviceInterfaceData, IntPtr.Zero, 0ref bufferSize, strtInterfaceData);
            //第二次调用传递返回值,调用即可成功
            IntPtr detailDataBuffer = Marshal.AllocHGlobal(bufferSize);
            SP_DEVICE_INTERFACE_DETAIL_DATA detailData = new SP_DEVICE_INTERFACE_DETAIL_DATA();
            detailData.cbSize = Marshal.SizeOf(typeof(SP_DEVICE_INTERFACE_DETAIL_DATA));
            Marshal.StructureToPtr(detailData, detailDataBuffer, false);
            result = SetupDiGetDeviceInterfaceDetail(hDevInfo, ref DeviceInterfaceData, detailDataBuffer, bufferSize, ref bufferSize, strtInterfaceData);
            if (result == false)
            {
                //break;
            }
            //获取设备路径访
              IntPtr pdevicePathName = (IntPtr)((int)detailDataBuffer + 4);
            string devicePathName = Marshal.PtrToStringAuto(pdevicePathName);
            HIDUSBAddress.Add(devicePathName);
            //index++;
            
//break;
            
//}

            
//连接设备文件
            int aa = CT_CreateFile(devicePathName);
            bool bb = USBDataRead(HidHandle);
        }

       //建立和设备的连接
       public unsafe int CT_CreateFile(string DeviceName)
        {
            HidHandle = CreateFile(
                DeviceName,
                GENERIC_READ,// | GENERIC_WRITE,//读写,或者一起
                FILE_SHARE_READ,// | FILE_SHARE_WRITE,//共享读写,或者一起
                0,
                OPEN_EXISTING,
                0,
                0);
            if (HidHandle == -1)
            {
                return 0;
            }
            else
            {
                return 1;
            }
        }
        
        //根据CreateFile拿到的设备handle访问文件,并返回数据
        public unsafe bool USBDataRead(int handle)
        {
            while (true)
            {
                uint read = 0;
                //注意字节的长度,我这里写的是8位,其实可以通过API获取具体的长度,这样安全点,
                  
//具体方法我知道,但是没有写,过几天整理完代码,一起给出来
                Byte[] m_rd_data = new Byte[8];
                bool isread = ReadFile((IntPtr)handle, m_rd_data, (uint)8ref read, IntPtr.Zero);
                //这里已经是拿到的数据了
                Byte[] m_rd_dataout = new Byte[read];
                Array.Copy(m_rd_data, m_rd_dataout, read);
            }
        }

OK,如果只是获取USB传过来的数据,这里已经足够了,但是有点要注意,2000和XP如果要获取HID键盘和鼠标的数据,readfile是不行的,;
在Win2000和WinXP下不能用CreateFile+ReadFile/WriteFile的方式来读写标准鼠标和标准键盘的数据,因为它们是系统独占的(Exlusive)。
如果你是其他HID类设备,比如游戏手柄或者自定义HID设备,都可以用上面的方式来收发数据,
怎么访问我暂时也不知道,估计要用它方法,看到有些软件是用截取的手段,估计是用钩子了吧。。


还有获取报文长度的代码,如果不确定报文长度,或者为了驱动适应变化,就用一下代码来确定报文的长度

//获取设备具体信息   
        [DllImport("hid.dll", SetLastError = true)]   
        private unsafe static extern int HidP_GetCaps(   
            int pPHIDP_PREPARSED_DATA,                    // IN PHIDP_PREPARSED_DATA  PreparsedData,   
            ref HIDP_CAPS myPHIDP_CAPS);                // OUT PHIDP_CAPS  Capabilities   
  
        [DllImport("hid.dll", SetLastError = true)]   
        private unsafe static extern int HidD_GetPreparsedData(   
            int hObject,                                // IN HANDLE  HidDeviceObject,   
            ref int pPHIDP_PREPARSED_DATA);           
  
        // HIDP_CAPS   
        [StructLayout(LayoutKind.Sequential)]   
        public unsafe struct HIDP_CAPS   
        {   
            public System.UInt16 Usage;                    // USHORT   
            public System.UInt16 UsagePage;                // USHORT   
            public System.UInt16 InputReportByteLength;   
            public System.UInt16 OutputReportByteLength;   
            public System.UInt16 FeatureReportByteLength;   
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)]   
            public System.UInt16[] Reserved;                // USHORT  Reserved[17];               
            public System.UInt16 NumberLinkCollectionNodes;   
            public System.UInt16 NumberInputButtonCaps;   
            public System.UInt16 NumberInputValueCaps;   
            public System.UInt16 NumberInputDataIndices;   
            public System.UInt16 NumberOutputButtonCaps;   
            public System.UInt16 NumberOutputValueCaps;   
            public System.UInt16 NumberOutputDataIndices;   
            public System.UInt16 NumberFeatureButtonCaps;   
            public System.UInt16 NumberFeatureValueCaps;   
            public System.UInt16 NumberFeatureDataIndices;   
        }   
  
 int reportLength = 8;   
  
            //获取设备发送的字节的长度(也有其他信息)   
            int myPtrToPreparsedData = -1;   
            int result1 = HidD_GetPreparsedData(handle, ref myPtrToPreparsedData);   
            HIDP_CAPS myHIDP_CAPS = new HIDP_CAPS();   
            int result2 = HidP_GetCaps(myPtrToPreparsedData, ref myHIDP_CAPS);   
            reportLength = myHIDP_CAPS.InputReportByteLength;  

再补充点,释放设备资源的时候需要用到

//释放设备的访问
        [DllImport("kernel32.dll")]
        internal static extern int CloseHandle(int hObject);
//释放设备
        [DllImport("setupapi.dll", SetLastError = true)]
        internal static extern IntPtr SetupDiDestroyDeviceInfoList(IntPtr DeviceInfoSet);

public void Dispost()
        {
            //释放设备资源(hDevInfo是SetupDiGetClassDevs获取的)
            SetupDiDestroyDeviceInfoList(hDevInfo);
            //关闭连接(HidHandle是Create的时候获取的)
            CloseHandle(HidHandle);
        }


  ok 了. 

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
华为设备默认console密码
admin@huawei.com Admin@huawei.com Admin@huawei huawei.com huawei@123 huawei Change_Me  网名:浩秦; 邮箱:root#landv.pw; 只要我能控制一個國家的貨幣發行,我不在乎誰制定法律。
1273 0
阿里云服务器端口号设置
阿里云服务器初级使用者可能面临的问题之一. 使用tomcat或者其他服务器软件设置端口号后,比如 一些不是默认的, mysql的 3306, mssql的1433,有时候打不开网页, 原因是没有在ecs安全组去设置这个端口号. 解决: 点击ecs下网络和安全下的安全组 在弹出的安全组中,如果没有就新建安全组,然后点击配置规则 最后如上图点击添加...或快速创建.   have fun!  将编程看作是一门艺术,而不单单是个技术。
4025 0
[C#]如何访问及调用类中私有成员及方法
原文:[C#]如何访问及调用类中私有成员及方法 本文为原创文章、源代码为原创代码,如转载/复制,请在网页/代码处明显位置标明原文名称、作者及网址,谢谢! 开发工具:VS2017 语言:C# DotNet版本:.
939 0
实战DeviceIoControl 之一:通过API访问设备驱动程序
<p>Q 在NT/2000/XP中,我想用VC编写应用程序访问硬件设备,如获取磁盘参数、读写绝对扇区数据、测试光驱实际速度等,该从哪里入手呢? </p> <p>A 在NT/2000/XP中,应用程序可以通过API函数DeviceIoControl来实现对设备的访问—获取信息,发送命令,交换数据等。利用该接口函数向指定的设备驱动发送正确的控制码及数据,然后分析它的响应,就可以达到我们的目的
2113 0
C# 访问USB(HID)设备
原文:C# 访问USB(HID)设备 二话不说,直接给代码,如果您真想做这方面的东西,还是稍微研究下,没有现成的好类用,就需要自己了解其原理 //引用空间using System;using System.
1645 0
《HTML5和JavaScript Web应用开发》——2.6 QA和设备测试
因为当前移动市场主要属于Android和iOS,进行基于WebKit的测试相当简单,我们可以像平常在桌面浏览器那样进行测试,然后在某个版本的WebKit支持的目标移动设备上运行。但是,在桌面版本的Chrome或者Safari上测试应用,并不意味着在所有基于WebKit的移动浏览器上都能正常工作,也不意味着WebKit能够完全代表移动Web。
1081 0
C#线程访问winform窗体控件
参考地址:http://www.cnblogs.com/jason-liu-blogs/archive/2012/09/08/2677008.html 添加: public Form() { InitializeComponent(); Control.
577 0
+关注
杰克.陈
一个安静的程序猿~
9798
文章
2
问答
文章排行榜
最热
最新
相关电子书
更多
文娱运维技术
立即下载
《SaaS模式云原生数据仓库应用场景实践》
立即下载
《看见新力量:二》电子书
立即下载