博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C++ MFC界面读写USB HID设备数据程序
阅读量:7056 次
发布时间:2019-06-28

本文共 8069 字,大约阅读时间需要 26 分钟。

发一个简单易用的界面,用来对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;

 

 

 

转载地址:http://cugol.baihongyu.com/

你可能感兴趣的文章
元素分类
查看>>
页面获取当前时间
查看>>
select,poll,epoll
查看>>
关于“foreach循环”中遇到的几个问题总结
查看>>
重温JSP学习笔记--El函数库
查看>>
模板引擎ejs的include方法
查看>>
NOIP2003 传染病控制
查看>>
bzoj千题计划316:bzoj3173: [Tjoi2013]最长上升子序列(二分+树状数组)
查看>>
python 3 中建立可迭代对象(making object iterable)
查看>>
linux: 堆排序和快速排序的整理
查看>>
请求数据传入(SpringMVC)
查看>>
第七篇 PHP编码规范
查看>>
队列(queue)
查看>>
jsHint-静态代码检查工具eclipse中使用
查看>>
SDE面试技巧之二:System Design
查看>>
测试中的小事情
查看>>
8.spring:事务管理(上):Spring的数据库编程、编程式事务管理
查看>>
PAT 1014
查看>>
Python异或加密字符串
查看>>
Cesium实现背景透明的方法
查看>>