前言
Windows下USB通讯,利用设备VID与PID查询设备,利用了windows的setupapi.lib与hid.lib库,开发时需要包含
#include <hidsdi.h>
#include <setupapi.h> 头文件
USB通讯类
CommUsb.h
#pragma once
#include <windows.h> //一定要加入该头文件
#include <iostream>
#include <vector>
extern "C" {
#include <hidsdi.h>
#include <setupapi.h>
}
#pragma comment (lib, "setupapi.lib")
#pragma comment (lib, "hid.lib")
using namespace std;
class CommUsb
{
public:
CommUsb();
~CommUsb();
//根据usb的VID与PID打开设备
BOOL DeviceOpen(HANDLE&handle, WORD wVID, WORD wPID);
//关闭设备,释放句柄类资源
void DeviceClose();
//向usb写入数据
BOOL DeviceWrite(LPCVOID lpBuffer, DWORD dwSize);
//从usb读取响应数据
void DeviceRead();
//读取数据线程
static void ReadThread(CommUsb *usb);
private:
HANDLE m_handle;
int m_size;
DWORD m_dwResult;
public:
BYTE m_rBuffer[64];
};
CommUsb.cpp
#include "CommUsb.h"
#include <thread>
CommUsb::CommUsb()
{
m_rBuffer[64] = { 0 };
m_handle = NULL;
m_size = 0;
m_dwResult = 0;
}
CommUsb::~CommUsb()
{
}
void CommUsb::ReadThread(CommUsb *usb)
{
ReadFile(usb->m_handle, usb->m_rBuffer, usb->m_size, &usb->m_dwResult, NULL);
}
BOOL CommUsb::DeviceOpen(HANDLE&handle, WORD wVID, WORD wPID)
{
BOOL bRet = FALSE;
GUID hidGuid;
HDEVINFO hardwareDeviceInfo;
SP_INTERFACE_DEVICE_DATA deviceInfoData;
PSP_INTERFACE_DEVICE_DETAIL_DATA functionClassDeviceData = NULL;
ULONG predictedLength = 0;
ULONG requiredLength = 0;
CloseHandle(handle);
handle = INVALID_HANDLE_VALUE;
deviceInfoData.cbSize = sizeof(SP_INTERFACE_DEVICE_DATA);
HidD_GetHidGuid(&hidGuid);
hardwareDeviceInfo = SetupDiGetClassDevs(&hidGuid, NULL, NULL, (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE));
for (int i = 0; i < 128; i++)
{
if (!SetupDiEnumDeviceInterfaces(hardwareDeviceInfo, 0, &hidGuid, i, &deviceInfoData)) continue;
SetupDiGetDeviceInterfaceDetail(hardwareDeviceInfo, &deviceInfoData, NULL, 0, &requiredLength, NULL);
predictedLength = requiredLength;
functionClassDeviceData = (PSP_INTERFACE_DEVICE_DETAIL_DATA)malloc(predictedLength);
if (!functionClassDeviceData) continue;
functionClassDeviceData->cbSize = sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA);
if (!SetupDiGetDeviceInterfaceDetail(hardwareDeviceInfo, &deviceInfoData, functionClassDeviceData, predictedLength, &requiredLength, NULL)) break;
handle = CreateFile(functionClassDeviceData->DevicePath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);// 倒数第二个参数可以指定为异步FILE_FLAG_OVERLAPPED 0为同步
// cout <<"devicePath"<<functionClassDeviceData->DevicePath<<endl;
if (handle != INVALID_HANDLE_VALUE)
{
HIDD_ATTRIBUTES attri;
HidD_GetAttributes(handle, &attri);
if ((attri.VendorID == wVID) && (attri.ProductID == wPID))
{
m_handle = handle; //将USB设备句柄存入类成员变量
bRet = TRUE;
break;
}
CloseHandle(handle);
handle = INVALID_HANDLE_VALUE;
}
}
SetupDiDestroyDeviceInfoList(hardwareDeviceInfo);
return bRet;
}
void CommUsb::DeviceClose()
{
CloseHandle(m_handle);
m_handle = INVALID_HANDLE_VALUE;
}
BOOL CommUsb::DeviceWrite(LPCVOID lpBuffer, DWORD dwSize)
{
if (m_handle == INVALID_HANDLE_VALUE)
{
//MessageBox(NULL,"数据写入失败","失败!",MB_OK);
return 0;
}
DWORD dwRet;
BOOL bRet;
PHIDP_PREPARSED_DATA PreparsedData;
HIDP_CAPS Capabilities;
HidD_GetPreparsedData(m_handle, &PreparsedData);
HidP_GetCaps(PreparsedData, &Capabilities);
m_rBuffer[0] = 0x00; //第一个字节为report Id,不能省略
memcpy(m_rBuffer + 1, lpBuffer, min(20, dwSize));
//这里写的长度要大于Capabilities.OutputReportByteLength
bRet = WriteFile(m_handle, m_rBuffer, Capabilities.OutputReportByteLength, &dwRet, NULL);
if (bRet)
{
//MessageBox(NULL,"写入数据成功","成功!",MB_OK);
}
return bRet;
}
void CommUsb::DeviceRead()
{
if (m_handle == INVALID_HANDLE_VALUE)
{
//MessageBox(NULL, "数据读取失败", "失败!", MB_OK);
//return 0;
}
PHIDP_PREPARSED_DATA PreparsedData;
HIDP_CAPS Capabilities;
HidD_GetPreparsedData(m_handle, &PreparsedData);
HidP_GetCaps(PreparsedData, &Capabilities);
//memcpy(&wBuffer[2], lpBuffer, min(6, dwSize));
COMMTIMEOUTS timeout;
timeout.ReadIntervalTimeout = 1000;
timeout.ReadTotalTimeoutConstant = 1000;
timeout.ReadTotalTimeoutMultiplier = 1000;
SetCommTimeouts(m_handle, &timeout);
//读的长度也一定要是Capabilities.OutputReportByteLength
//线程函数参数初始化
m_size = Capabilities.OutputReportByteLength;
thread Rthread(ReadThread, this);
Rthread.join();
//return bRet;
}
测试示例
Win32测试
#include "../common/CommUsb.h"
int main()
{
CommUsb Myusb;
HANDLE handle = NULL;
if (Myusb.DeviceOpen(handle, 0x0483, 0x5750) == FALSE)
{
MessageBox(NULL, "打开设备失败", "错误", MB_OK);
}
BYTE str[20] = { 0 };
/*str[0] = 0x00;
str[1] = 0x80;
str[2] = 0xAA;
str[3] = 0xFD;
str[4] = 0x02;
str[5] = 0x60;
str[6] = 0x06;
str[7] = 0x66;*/
str[0] = 0x00;
str[1] = 0x80;
str[2] = 0xAA;
str[3] = 0xFD;
str[4] = 0x02;
str[5] = 0x60;
str[6] = 0x07;
str[7] = 0x67;
Myusb.DeviceWrite(str, 20);
Myusb.DeviceRead();
for (int i = 0; i < sizeof(Myusb.m_rBuffer); i++)
{
printf("%02hhx ", Myusb.m_rBuffer[i]);
}
cout << endl;
Myusb.DeviceClose();
system("pause");
return 0;
}
MFC测试
// USBMfcTestDlg.cpp : 实现文件
//
#include "stdafx.h"
#include "USBMfcTest.h"
#include "USBMfcTestDlg.h"
#include "afxdialogex.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// 用于应用程序“关于”菜单项的 CAboutDlg 对话框
class CAboutDlg : public CDialogEx
{
public:
CAboutDlg();
// 对话框数据
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_ABOUTBOX };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()
// CUSBMfcTestDlg 对话框
CUSBMfcTestDlg::CUSBMfcTestDlg(CWnd* pParent /*=NULL*/)
: CDialogEx(IDD_USBMFCTEST_DIALOG, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
m_handle = NULL;
}
void CUSBMfcTestDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_EDIT_VID, m_Edit_VID);
DDX_Control(pDX, IDC_EDIT_PID, m_Edit_PID);
DDX_Control(pDX, IDC_EDIT_SEND, m_Edit_Send);
DDX_Control(pDX, IDC_EDIT_RECIEVE, m_Edit_Recieve);
}
BEGIN_MESSAGE_MAP(CUSBMfcTestDlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_oPEN, &CUSBMfcTestDlg::OnBnClickedopen)
ON_BN_CLICKED(IDC_BUTTON1, &CUSBMfcTestDlg::OnBnClickedButton1)
ON_BN_CLICKED(IDC_BUTTON2, &CUSBMfcTestDlg::OnBnClickedButton2)
ON_BN_CLICKED(IDC_CLOSE, &CUSBMfcTestDlg::OnBnClickedClose)
ON_BN_CLICKED(IDC_SEND, &CUSBMfcTestDlg::OnBnClickedSend)
ON_WM_TIMER()
END_MESSAGE_MAP()
// CUSBMfcTestDlg 消息处理程序
BOOL CUSBMfcTestDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 将“关于...”菜单项添加到系统菜单中。
// IDM_ABOUTBOX 必须在系统命令范围内。
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
// TODO: 在此添加额外的初始化代码
//初始化各个输入框的初始值
m_Edit_VID.SetWindowText("0483");
m_Edit_PID.SetWindowText("5750");
m_Edit_Send.SetWindowText("0080AAFD02600666");
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
void CUSBMfcTestDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialogEx::OnSysCommand(nID, lParam);
}
}
// 如果向对话框添加最小化按钮,则需要下面的代码
// 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序,
// 这将由框架自动完成。
void CUSBMfcTestDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// 使图标在工作区矩形中居中
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// 绘制图标
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
}
//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CUSBMfcTestDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
void CUSBMfcTestDlg::OnBnClickedopen()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData();
CString StrVid,StrPid,StrRecv;
WORD Hvid = 0,Hpid = 0;
m_Edit_VID.GetWindowTextA(StrVid);
m_Edit_PID.GetWindowTextA(StrPid);
Hvid = _tcstoul(StrVid, 0, 16);
Hpid = _tcstoul(StrPid, 0, 16);
if (StrVid.IsEmpty() || StrPid.IsEmpty())
{
Hvid = 0x0483;
Hpid = 0x5750;
}
if (MyUsb.DeviceOpen(m_handle, Hvid, Hpid) == FALSE)
{
m_Edit_Recieve.GetWindowTextA(StrRecv);
m_Edit_Recieve.SetWindowTextA(StrRecv + "USB设备打开失败\r\n");
}
else
{
m_Edit_Recieve.GetWindowTextA(StrRecv);
m_Edit_Recieve.SetWindowTextA(StrRecv + "USB设备打开成功\r\n");
}
}
void CUSBMfcTestDlg::OnBnClickedButton1()
{
// TODO: 在此添加控件通知处理程序代码
m_Edit_Send.SetWindowTextA("");
}
void CUSBMfcTestDlg::OnBnClickedButton2()
{
// TODO: 在此添加控件通知处理程序代码
m_Edit_Recieve.SetWindowTextA("");;
}
void CUSBMfcTestDlg::OnBnClickedClose()
{
// TODO: 在此添加控件通知处理程序代码
MyUsb.DeviceClose();
}
//send
void CUSBMfcTestDlg::OnBnClickedSend()
{
// TODO: 在此添加控件通知处理程序代码
CString StrSend = "";
char SendHex[20] = { 0 };
m_Edit_Send.GetWindowTextA(StrSend);
Str2Hex(StrSend, SendHex);
MyUsb.DeviceWrite(SendHex, 8);
SetTimer(1, 1000, NULL);
}
void CUSBMfcTestDlg::OnTimer(UINT_PTR nIDEvent)
{
CString StrRec=" ",StrTemp=" ",StrPost=" ";
if (nIDEvent==1)
{
MyUsb.DeviceRead();
for (int i=0;i<sizeof(MyUsb.m_rBuffer);i++)
{
StrTemp.Format("%02x ", MyUsb.m_rBuffer[i]);
if ((i+1)%25==0)
{
StrRec += "\r\n";
}
StrRec += StrTemp;
}
m_Edit_Recieve.GetWindowTextA(StrPost);
m_Edit_Recieve.SetWindowTextA(StrRec + "\r\n" + StrPost);
KillTimer(1);
}
}
int CUSBMfcTestDlg::Str2Hex(CString str, char* data)
{
int t, t1;
int rlen = 0, len = str.GetLength();
//data.SetSize(len/2);
for (int i = 0; i < len;)
{
char l, h = str[i];
if (h == ' ')
{
i++;
continue;
}
i++;
if (i >= len)
break;
l = str[i];
t = HexChar(h);
t1 = HexChar(l);
if ((t == 16) || (t1 == 16))
break;
else
t = t * 16 + t1;
i++;
data[rlen] = (char)t;
rlen++;
}
return rlen;
}
char CUSBMfcTestDlg::HexChar(char c)
{
if ((c >= '0') && (c <= '9'))
return c - 0x30;
else if ((c >= 'A') && (c <= 'F'))
return c - 'A' + 10;
else if ((c >= 'a') && (c <= 'f'))
return c - 'a' + 10;
else
return 0x10;
}
运行效果:
源代码下载
https://download.csdn.net/download/qq_22642239/12736524
文章参考:网络资源