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, 0, ref 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)8, ref 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);
}
复制代码

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: c是英文字母表中的第三个字母,它的发音是/ci:/。它除了在拼写单词中使用外,还有一些其他的意义和应用。 首先,c可以作为罗马数字中的100,表示一个世纪的数量。例如,20世纪可以用罗马数字表示为XX。 此外,c还是化学元素周期表中的一个元素符号,代表着碳元素。碳是一种非金属元素,它广泛存在于自然界中,是地球上许多有机物的基础。 另外,在计算机编程中,C是一种编程语言的名称。C语言是一种通用的、高级的编程语言,它被广泛应用于软件开发领域。C语言为程序员提供了丰富的功能和灵活性,可以用来编写各种类型的应用程序。 此外,在音乐领域,C是一个音符,代表着标准音阶中的do。C是一个非常重要的音符,它是音乐中基本的音符之一,用于构建和组合各种乐曲。 总的来说,c是一个非常常见和有多重意义的字母。无论是在拼写单词、表示罗马数字、代表元素符号、编程语言还是音乐中,c都发挥着重要的作用。 ### 回答2: 我将尽力用300字来回答您的问题。 "c"这个字母是英语字母表中的第三个字母。在英语中,它的发音是/k/,类似于“克”的发音。它是一个辅音字母,表示声带振动。 在数学中, "c"有着特殊的意义,它代表着圆周率,也就是3.14159。圆周率是一个无理数,表示圆的周长与直径的比例。它在计算几何、物理和工程学中具有重要的应用。 在计算机科学中, "c"也有着重要的含义。它是一种编程语言的名称,C语言。C语言是一种广泛应用的、高级的、通用的编程语言。它由贝尔实验室的Dennis Ritchie于1972年开发,并在计算机科学领域得到了广泛的应用。C语言是很多其他编程语言的基础,例如C++、Java等。 除此之外, "c"还可能有其他含义,具体要根据语境而定。例如,在音乐中, "c"可以代表C大调,是一个音乐音高的符号。 总之, "c"这个字母在英语中有特殊的发音和位置,同时在数学和计算机科学中有着重要的含义。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值