C++ MFC界面读写USB HID设备数据程序

发一个简单易用的界面,用来对USB HID设备(比如说游戏手柄,控制面板等)读写数据,一般情况下面板上有一些LED,可以帮助我们测试读写是否正确。另外,需要可以修改vendorID和prodcutID,这样一个界面,可以用于测试多个HID设备。

过程分成3步:1: 列举出所有的HID设备,2: 循环读取HID设备数据,3: 向HID设备写数据,下面我把三部分的程序单独分开,方便大家学习!

在讲具体程序之前,先说一下visual studio的环境配置(我用的是2008版本)!
<下面程序需要包含DDK一部分头文件和库文件>

第一步:列举所有的HID设备:


m_ctllHIDdevices.ResetContent(); //这是MFC里面一个list控件,用来显示所有的HID设备的,如果你没有界面,可以不需要此行
UpdateData(FALSE); //更新界面
CString temp;
int Count = 0; //Total number of devices found
DWORD strSize=0,requiredSize=0;
BOOL result1,result2;
ULONG DeviceInterfaceDetailDataSize;
//定义一些变量,以后会用到
SP_DEVINFO_DATA DeviceInfoData;
SP_DEVICE_INTERFACE_DATA  DeviceInterfaceData;
PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData;
//PSP_DEVICE_INTERFACE_DETAIL_DATA test;
//第一步:获取deviceID
GUID deviceId;
HidD_GetHidGuid(&deviceId);

//第二步:获取设备信息
HDEVINFO handle;
handle = SetupDiGetClassDevs(&deviceId, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); //Get only HID devices


//第三步:对所有的设备进行枚举
//SetupDiEnumDeviceInterfaces();
result1=false; //定义一些变量
result2=false;
CString temp11="";
do
{
  
        DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
        result1 = SetupDiEnumDeviceInterfaces(
                        handle,
                        NULL, // IN PSP_DEVINFO_DATA  DeviceInfoData,  OPTIONAL
                        &deviceId,
                        Count,
                        &DeviceInterfaceData
                         );
       //获得设备详细数据(初步)
       SetupDiGetDeviceInterfaceDetail(handle,
          &DeviceInterfaceData,
          NULL,
          0,
          &strSize,
          NULL);
      requiredSize=strSize;
      DeviceInterfaceDetailData=(PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(requiredSize);
      DeviceInterfaceDetailData->cbSize=sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
      DeviceInfoData.cbSize=sizeof(SP_DEVINFO_DATA);

      //再次获得详细数据
      result2=SetupDiGetDeviceInterfaceDetail(handle,
            &DeviceInterfaceData,
            DeviceInterfaceDetailData,
            strSize,
            &requiredSize,
            &DeviceInfoData);

       //获得设备路径(最重要的部分)
       temp=DeviceInterfaceDetailData->DevicePath;
       UpdateData(FALSE);
       m_ctllHIDdevices.AddString(temp);
       Count++;
   } while (result1);


      UpdateData(false);


到这个时候为止,所有的设备路径,都会显示在窗口的listbox里面!

 

第二步:循环读取HID设备数据(根据用户提供的HID的vendorID和productID),并且把字节解码成二进制,在MFC界面上用LED展示:

为了不影响主线程的运行,我把读取数据的操作,放在一个子线程里!每隔50ms去读取一次数据!

首先创建一个线程:
        HANDLE hThread1;
        bStopHID=false; //这个变量,以后用来停止线程
        UpdateData(true); //更新界面,获取变量
        UpdateData(false);
        hThread1 = CreateThread(NULL,0,Thread_Enable_Read,(LPVOID)this, NULL, NULL);

在线程的程序里:

       CusbhidDlg *p = ( CusbhidDlg *)pvParam; //获取主窗口的指针,用来调用主窗口的变量和函数
        
        p->UpdateData(true);
        p->bStopHID=false;


        CString temp;
        CString DevicePath;
        temp="";

        int Count = 0; //Total number of devices found
        DWORD strSize=0,requiredSize=0;
        BOOL result1,result2;
        ULONG DeviceInterfaceDetailDataSize;        
        SP_DEVINFO_DATA DeviceInfoData;
        SP_DEVICE_INTERFACE_DATA  DeviceInterfaceData;
        PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData;
        //PSP_DEVICE_INTERFACE_DETAIL_DATA test;
        //1
        GUID deviceId;
        HidD_GetHidGuid(&deviceId);



        int venderID=p->v_eVendorID; //从窗口里获取用户输入的VendorID
        int productID=p->v_eProductID;//从窗口里获取用户输入的ProductID

        
        unsigned char inbuffer[2]; //用来存放读取的数据,请在这里定义你自己需要的长度,我每次读一个字节进来
        unsigned long numBytesReturned;
        HIDD_ATTRIBUTES devAttr;
        PHIDP_PREPARSED_DATA PreparsedData;
        HIDP_CAPS Capabilities;
        int readValue;
        bool LED;
        int flag=0;
        
        
        //2
        HDEVINFO handle;
        handle = SetupDiGetClassDevs(&deviceId, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); //Get only HID devices
        int i=0;
        int j=p->m_ctllHIDdevices.GetCount();
        for (i=0;i<p->m_ctllHIDdevices.GetCount();i++)
        {
                p->m_ctllHIDdevices.GetText(i,temp);
                DevicePath=temp;

               //CreateFile是非常重要的一步,用来建立于HID通信的句柄
                HANDLE hCom = CreateFile (
                DevicePath,
                GENERIC_READ | GENERIC_WRITE,
                FILE_SHARE_READ | FILE_SHARE_WRITE,
                NULL,
                OPEN_EXISTING, 0,
                NULL);

                if (hCom == INVALID_HANDLE_VALUE)

                {            
                   //AfxMessageBox("Invalide Device Path...");
                   continue;

                }

                devAttr.Size=sizeof(HIDD_ATTRIBUTES);

                if (!HidD_GetAttributes(hCom,&devAttr))

                {

                        CloseHandle(hCom);
                        AfxMessageBox("Cannot get the parameters of the HID...");
                        return 0;   

                }

                //temp.Format("Vendor ID: %d, Product ID:%d",devAttr.VendorID,devAttr.ProductID); //Compare with the Vendor ID and Product ID from Nakamura-san
                //AfxMessageBox(temp);

        
                if (!HidD_GetPreparsedData(hCom,&PreparsedData))
                {

                        CloseHandle(hCom);
                        AfxMessageBox("Cannot get the Preparsed Data...");
                        return 0;   

                }
        
               
                if(!HidP_GetCaps(PreparsedData,&Capabilities))
                {

                        CloseHandle(hCom);
                        AfxMessageBox("Cannot get the Cap Data...");
                        return 0;   

                }
               if (devAttr.VendorID == venderID && devAttr.ProductID == productID)
                {
                                while(1)
                                {


                                        result1 = ReadFile(hCom, &inbuffer[0], Capabilities.InputReportByteLength, &numBytesReturned, 0);
                                        temp=inbuffer;

                                        //p->m_eDataRead=CString(inbuffer);
                                        //p->UpdateData(false);
                                        if(!result1)
                                        {
                                                AfxMessageBox("Cannot Read Data...");
                                                return 0;   

                                       
                                        }

                                        readValue=inbuffer[1];
                                        p->m_eDataRead.Format("%d",readValue);
                                        //下面是我把数据从10进制转换成二进制,并且点亮LED (一个字节有8个bits,可以点亮8个LED
                                        for (int k=0;k<8;k++)
                                        {
                                                
                                                flag=readValue%2;
                                                readValue=readValue/2;        
                                                
                                                if (k==0)
                                                {
                                                        if (flag==0)
                                                                p->m_sDynLED0.SwitchOff();
                                                        else
                                                                p->m_sDynLED0.SwitchOn();

                                                }
                                                else if (k==1)
                                                {
                                                        if (flag==0)
                                                                p->m_sDynLED1.SwitchOff();
                                                        else
                                                                p->m_sDynLED1.SwitchOn();

                                                }
                                                

                                                else if (k==2)
                                                {
                                                        if (flag==0)
                                                                p->m_sDynLED2.SwitchOff();
                                                        else
                                                                p->m_sDynLED2.SwitchOn();

                                                }
                                                
                                                else if (k==3)
                                                {
                                                        if (flag==0)
                                                                p->m_sDynLED3.SwitchOff();
                                                        else
                                                                p->m_sDynLED3.SwitchOn();

                                                }
                                                

                                                else if (k==4)
                                                {
                                                        if (flag==0)
                                                                p->m_sDynLED4.SwitchOff();
                                                        else
                                                                p->m_sDynLED4.SwitchOn();

                                                }
                                                

                                                else if (k==5)
                                                {
                                                        if (flag==0)
                                                                p->m_sDynLED5.SwitchOff();
                                                        else
                                                                p->m_sDynLED5.SwitchOn();

                                                }
                                                

                                                else if (k==6)
                                                {
                                                        if (flag==0)
                                                                p->m_sDynLED6.SwitchOff();
                                                        else
                                                                p->m_sDynLED6.SwitchOn();

                                                }
                                                

                                                else if (k==7)
                                                {
                                                        if (flag==0)
                                                                p->m_sDynLED7.SwitchOff();
                                                        else
                                                                p->m_sDynLED7.SwitchOn();

                                                }
                                


                                        }

                                        p->UpdateData(false);
                                       

                                        ::Sleep(50);
                                        //判断用户是否点击停止按钮,若是,则退出
                                        if(p->bStopHID)
                                        {

                                        AfxMessageBox("stopped...");
                                        return 0;

                                        }

                                }
                }
        }

        if (i==j)
        {
                AfxMessageBox("There is no such HID device...");

        }
        return 0;

第三步:向HID设备写数据(根据用户提供的HID的vendorID和productID),用户输入的是二进制数据:

与读的程序一样,唯一区别就是红色那部分!

UpdateData(true);
bStopHID=false;

CString temp;
CString DevicePath;
temp="";
int Count = 0; //Total number of devices found
DWORD strSize=0,requiredSize=0;
BOOL result1,result2;
ULONG DeviceInterfaceDetailDataSize;
SP_DEVINFO_DATA DeviceInfoData;
SP_DEVICE_INTERFACE_DATA  DeviceInterfaceData;
PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData;
//PSP_DEVICE_INTERFACE_DETAIL_DATA test;
//1
GUID deviceId;
HidD_GetHidGuid(&deviceId);

int venderID=v_eVendorID;
int productID=v_eProductID;

unsigned char inbuffer[2];
unsigned long numBytesReturned;
HIDD_ATTRIBUTES devAttr;
PHIDP_PREPARSED_DATA PreparsedData;
HIDP_CAPS Capabilities;
int readValue;
bool LED;
int flag=0;
inbuffer[0]=0;
//把界面里的二进制转换成10进制
inbuffer[1]=m_eByte0*1+m_eByte1*2+m_eByte2*4+m_eByte3*8+m_eByte4*16+m_eByte5*32+m_eByte6*64+m_eByte7*128;

v_eDataToWrite=inbuffer[1];
UpdateData(false);

//2
HDEVINFO handle;
handle = SetupDiGetClassDevs(&deviceId, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); //Get only HID devices
int i=0;
int j=m_ctllHIDdevices.GetCount();
for (i=0;i<m_ctllHIDdevices.GetCount();i++)
{
  m_ctllHIDdevices.GetText(i,temp);
  DevicePath=temp;
  HANDLE hCom = CreateFile (
              DevicePath,
              GENERIC_READ | GENERIC_WRITE,
              FILE_SHARE_READ | FILE_SHARE_WRITE,
              NULL,
              OPEN_EXISTING, 0,
              NULL);
  if (hCom == INVALID_HANDLE_VALUE)
  {            
     //AfxMessageBox("Invalide Device Path...");
           continue;
  }
  devAttr.Size=sizeof(HIDD_ATTRIBUTES);
  if (!HidD_GetAttributes(hCom,&devAttr))
  {
   CloseHandle(hCom);
   AfxMessageBox("Cannot get the parameters of the HID...");
   return;   
  }
  //temp.Format("Vendor ID: %d, Product ID:%d",devAttr.VendorID,devAttr.ProductID); //Compare with the Vendor ID and Product ID from Nakamura-san
  //AfxMessageBox(temp);

  if (!HidD_GetPreparsedData(hCom,&PreparsedData))
  {
   CloseHandle(hCom);
   AfxMessageBox("Cannot get the Preparsed Data...");
   return;   
  }

  
  if(!HidP_GetCaps(PreparsedData,&Capabilities))
  {
   CloseHandle(hCom);
   AfxMessageBox("Cannot get the Cap Data...");
   return;   
  }


// Write File
  if (devAttr.VendorID == venderID && devAttr.ProductID == productID)
  {
   result1 = WriteFile(hCom, inbuffer, 2, &numBytesReturned, NULL);
   //temp=inbuffer;
   //p->m_eDataRead=CString(inbuffer);
   //p->UpdateData(false);
   if(!result1)
   {
      AfxMessageBox("Cannot Write Data...");
      return;   
     
   }
   AfxMessageBox("Suncess...");
   break;
   
  }
}
if (i==j)
{
  AfxMessageBox("There is no such HID device...");
}
return;

 

 

 

转载于:https://www.cnblogs.com/MMLoveMeMM/articles/3216088.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/433335.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

nano-pc-t1 4412 显示驱动分析

1. 和其它内核代码类似。 显示驱动的分析都是由 drivers/video/fbmem.c开始&#xff0c;fbmem.c是显示驱动的抽象&#xff0c;实际只是一个框架性的东西。 fbmem_init 中实现了一个字符设备驱动&#xff0c;并创建了class&#xff0c;但是没有生成设备文件。 这个字符设备驱动的…

mysql中索引约束有哪些_Mysql中索引和约束的示例语句

外键查询一个表的主键是哪些表的外键SELECTTABLE_NAME,COLUMN_NAME,CONSTRAINT_NAME,REFERENCED_TABLE_NAME,REFERENCED_COLUMN_NAMEFROMINFORMATION_SCHEMA.KEY_COLUMN_USAGEWHERETABLE_SCHEMA mydbnameAND REFERENCED_TABLE_NAME 表名;导出所有外键语句SELECTCONCAT(ALTER …

taskkill无法终止进程 拒绝访问_解决删除文件时,提示无法删除的问题

有时我们想删除某个程序文件夹&#xff0c;或是卸载后残留的一些 .dll 等后缀的文件&#xff0c;却一直提示 “运行中” 、 “权限不足” &#xff0c;甚至用第三方的强力删除功能都无法删除。这时我们可以用系统自带的命令行功能&#xff0c;使用几个简单的小命令就可以彻底删…

javascript删除数组里的对象

Array.prototype.del function(value) {//删除数组中指定的元素&#xff0c;返回新数组function hasValue(array, value) {for(var i 0; i < array.length; i) {if (value array[i]) {return i;}}return -1;}var position hasValue(this, value);var temp new Array ;i…

擦窗机器人测试标准_擦窗机器人,我选择玻妞的三个理由!

很多人都喜欢高层&#xff0c;一览无遗&#xff0c;广阔风景&#xff01;可现实是无论什么高层湖景都会被窗户上日积月累的灰尘遮挡的严严实实&#xff0c;每次擦窗都累到怀&#xff01;疑&#xff01;人&#xff01;生&#xff01;于是一年又一年&#xff0c;你想要的风景始终…

Oracle客户端与java_Oracle 谈 JavaFX 及 Java 客户端技术的未来

原标题&#xff1a;Oracle 谈 JavaFX 及 Java 客户端技术的未来据 Oracle 博客称&#xff0c;从 JDK 11 开始&#xff0c;Oracle 将从 JDK 中删除 JavaFX&#xff0c;但在 2022 年之前&#xff0c;Oracle 还会继续为 JDK 8 中的 JavaFX 提供商业支持。2011 年&#xff0c;JavaF…

基于Passthru的NDIS开发的个人理解

基于Passthru的NDIS开发的个人理解 这几天对NDIS的学习&#xff0c;基本思路是&#xff1a;首先熟悉理论知识→然后下载一个例子进行研究→最后例子自己模仿扩展→最最后尝试自己写一个新的。 Passthru是微软NDIS自己写的一个框架驱动&#xff0c;NDIS开发者可以在此框架上进行…

Conversion to Dalvik format failed with error 1

如题&#xff0c;解决办法是将工程中的 Android Private Libraries移除即可

char类型包括数字吗java_Java char 与 Character

1. java中char类型占2个字节、16位能够存放汉子&#xff0c;字母和数字占一个字节&#xff0c;一个字节8位&#xff0c;中文占2个字节&#xff0c;16位&#xff1b;java2. char类型赋值编码char a’a’; //任意单个字符&#xff0c;加单引号。char a’中’;//任意单个中文字&am…

HDOJ 4253 Two Famous Companies 二分+MST

题目意思&#xff1a;给出n个点&#xff0c;m条边&#xff0c;边分为两种&#xff0c;一种是A公司的&#xff0c;一种是B公司的。边上有权值&#xff0c; 问用n-1条边把n个点连起来的最小费用是多少&#xff0c;其中A公司的边刚好有k条。题目保证有解。 题解&#xff1a;题目意…

低代码开发平台_低代码开发平台测评——伙伴云

​本次测评的产品严格来说不算低代码开发平台&#xff0c;它自己给自己的定位更多是全流程数据生产力平台。不过它依然具备应用搭建的关键要素&#xff0c;而且在数据管理方面还比较出彩&#xff0c;所以不能放过它——伙伴云&#xff0c;这款由Discuz&#xff01;主创团队操刀…

java 返回js_如何基于java或js获取URL返回状态码

这篇文章主要介绍了如何基于java或js获取URL返回状态码,文中通过示例代码介绍的非常详细&#xff0c;对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参fgLAeaGAH考下描述&#xff1a;使用java或者js访问某个网站&#xff0c;返回状态码1.java实现// 用getResponse…

Linux 信号signal处理函数

alarm&#xff08;设置信号传送闹钟&#xff09; 相关函数 signal&#xff0c;sleep 表头文件 #include<unistd.h> 定义函数 unsigned int alarm(unsigned int seconds); 函数说明 alarm()用来设置信号SIGALRM在经过参数seconds指定的秒数后传送给目前的进程。如果参数se…

我的开发环境配置经验

我的开发环境配置经验 http://chinasf.cnblogs.com/archive/2010/01/07/1640960.html本人做开发&#xff0c;偶尔重装下系统&#xff0c;比如换电脑了&#xff1b;或者是visual studio 该升级了&#xff0c;或者是系统坏掉了&#xff1b;每次装好后&#xff0c;我都会做备份&am…

python database ioerror_python – IOError:[Errno 2]没有这样的文件或...

我试图在我的MySQL数据库的表的路径中添加所有种子文件的一些信息,但似乎我有一些PATH问题.你可以看到有完整的路径,它甚至检测到“charlie.torrent”,所以我真的不明白是什么问题.这是我的代码&#xff1a;#!/usr/bin/env python# -*- coding: utf-8 -*-import mysql.connecto…

A20修改串口设备文件

目标&#xff1a;将uart2的设备文件修改为ttyS6&#xff0c;反之亦然 将uart1的设备文件修改为ttyS5&#xff0c;反之亦然 修改“drivers/tty/tty_io.c"文件 找到tty_line_name(driver,index,name)这行&#xff0c;这行是用来生成设备文件的名称。 在这行前加上一下几句…

php 返回数组 键名,php array_keys 返回数组的键名

array_keys返回数组中部分的或所有的键名说明array array_keys ( array $array [, mixed $search_value [, bool $strict false ]] )array_keys() 返回 $array 数组中的数字或者字符串的键名。如果指定了可选参数 search_value&#xff0c;则只返回该值的键名。否则 $array 数…

C#中ref与out区别

static void Main(string[] args){//out testint a, b;//out使用前&#xff0c;变量可以不赋值outTest(out a, out b);Console.WriteLine("a{0};b{1}", a, b);int c 11, d 22;outTest(out c, out d);Console.WriteLine("c{0};d{1}", c, d);//ref testint…

安装好了python环境后如何打开_教你如何安装Python环境

欢迎同学们来到Python编程世界。人生苦短&#xff0c;Python是岸。01 初见PythonPython编程语言是荷兰人Guido van Rossum在1990年代开发出来的。Gudio拥数学和计算机双硕士学位&#xff0c;但他更喜欢计算机。当时Gudio觉得现有的编程语言无法做到既实用又能够轻松编程&#x…

A20串口驱动分析

串口驱动的整体框架实际上和显示驱动类似 驱动程序是一个字符设备&#xff0c;驱动的实质内容都是在一个平台总线设备驱动程序里 1. 串口驱动的分析&#xff0c;从"drivers/tty/serial/8250/8250.c"开始 serial8250_init为入口函数&#xff0c;从这个函数一路分析下…