Qt驱动USB设备的方法
- 找设备厂商要动态库和接口文档;
- 找对应USB设备的Qt库,eg:QCamera、QPrinter等
- USB转串口,使用QtSerialPort;
- 使用第三方QtUSB库(Qt本身没有封装USB的库);
- Qt + windows API
如果开发过程中,遇到没有相关文档、Qt没有对应的设备库、不能转串口、深爱自己的代码不想给她塞太多奇怪的东西的情况,那我们就要想想第5种办法的可行性了;下面分成三部分简单介绍一下第五种办法(太深入的我暂时也不懂,看个乐子);
.pro
SetupAPI是一个被用来执行安装设备的一系列操作的方法的集合
unix|win32: LIBS += -lsetupapi
.h
#ifndef USBPRINTER_H
#define USBPRINTER_H
#include <QWidget>
#include <windows.h>
#include <string>
#include <IOSTREAM>
#include <winioctl.h>
#include <setupapi.h>
#include <stdio.h>
#include <tchar.h>
#include <QString>
#endif // USBPRINTER_H
.cpp
1. 获取设备信息GetDevicePath,如"\\?\usb#vid_8087&pid_0aaa#5&21cd2d89&0&14#{a5dcbf10-6530-11d2-901f-00c04fb951ed}";设备信息如下:
设备ID:8087
厂商ID:0aaa
设备序列号:5&21cd2d89&0
2. 再将指定设备信息完整的传入初始化函数InitPort的第一个参数;
3. 最后就是简单的按照对待文件的方式处理该设备;
//获取设备信息
bool USBPrinter::GetDevicePath(QStringList &USBDeviceList, QString &p_sErrMsg)
{
const GUID GUID_DEVINTERFACE_LIST[] =
{
{ 0xA5DCBF10, 0x6530, 0x11D2, { 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED } }, //USB设备的GUID
{ 0x53f56307, 0xb6bf, 0x11d0, { 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b } }
};
LPGUID lpGuid = (LPGUID)&GUID_DEVINTERFACE_LIST;
HDEVINFO hDevInfoSet;
SP_DEVINFO_DATA spDevInfoData;
SP_DEVICE_INTERFACE_DATA ifData;
PSP_DEVICE_INTERFACE_DETAIL_DATA pDetail;
int iTotle;
bool bResult;
// 取得一个该GUID相关的设备信息集句柄
hDevInfoSet = ::SetupDiGetClassDevs(lpGuid, //class GUID
NULL, //无关键字
NULL, //不指定父窗口句柄
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);//目前存在的设备
//失败
if(hDevInfoSet == INVALID_HANDLE_VALUE)
{
p_sErrMsg = "获取设备失败";
return false;
}
//申请设备接口数据空间
pDetail = (PSP_DEVICE_INTERFACE_DETAIL_DATA)::GlobalAlloc(LMEM_ZEROINIT, INTERFACE_DETAIL_SIZE);
pDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
iTotle = -1;
bResult = true;
//设备序号=0,1,2... 逐一测试设备接口,到失败为止
while(bResult)
{
iTotle++;
spDevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
// 枚举符合该GUID的设备接口
bResult = ::SetupDiEnumDeviceInfo(
hDevInfoSet, // 设备信息集句柄
(ULONG)iTotle, // 设备信息集里的设备序号
&spDevInfoData); // 设备接口信息
if(bResult)
{
DWORD DataT ;
TCHAR buf[MAX_PATH];
DWORD nSize = 0;
wstring wsName=QString("Unknown").toStdWString();
//get Friendly Name or Device Description
if( SetupDiGetDeviceRegistryProperty(hDevInfoSet, &spDevInfoData,
SPDRP_FRIENDLYNAME, &DataT, (PBYTE)buf, sizeof(buf), &nSize) )
{
}
else if( SetupDiGetDeviceRegistryProperty(hDevInfoSet, &spDevInfoData,
SPDRP_DEVICEDESC, &DataT, (PBYTE)buf, sizeof(buf), &nSize) )
{
}
else
{
lstrcpy(buf,wsName.c_str());
}
QString sTemp = QString::fromWCharArray(buf);
//是否为目标设备
if(sTemp == "xxx")
continue;
ifData.cbSize = sizeof(ifData);
//枚举符合该GUID的设备接口
bResult = ::SetupDiEnumDeviceInterfaces(
hDevInfoSet, //设备信息集句柄
NULL, //不需额外的设备描述
lpGuid, //GUID
(ULONG)iTotle, //设备序号
&ifData); //设备接口信息
if(bResult)
{
//取得该设备接口的细节(设备路径)
bResult = SetupDiGetInterfaceDeviceDetail(
hDevInfoSet, // 设备信息集句柄
&ifData, // 设备接口信息
pDetail, // 设备接口细节(设备路径)
INTERFACE_DETAIL_SIZE, // 输出缓冲区大小
NULL, // 不需计算输出缓冲区大小(直接用设定值)
NULL); // 不需额外的设备描述
if(bResult)
{
//复制设备路径到输出缓冲区
USBDeviceList.append(QString::fromWCharArray(pDetail->DevicePath));
}
}
}
}
//释放设备接口数据空间
::GlobalFree(pDetail);
//关闭设备信息集句柄
::SetupDiDestroyDeviceInfoList(hDevInfoSet);
return true;
}
//初始化USB端口
bool USBPrinter::InitPort(QString p_sUSBPort, QString &p_sErrMsg)
{
//获取句柄
wstring wsPort = p_sUSBPort.toStdWString();
m_hPort = CreateFile(wsPort.c_str(),GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
//打开端口失败
if(m_hPort == INVALID_HANDLE_VALUE)
{
p_sErrMsg = "打开端口失败";
return false;
}
else
{
//设置端口缓冲
SetupComm(m_hPort, 1024, 1024);
//设定通讯端口超时参数
COMMTIMEOUTS tmouts;
tmouts.ReadIntervalTimeout = 100;
tmouts.ReadTotalTimeoutMultiplier = 100;
tmouts.ReadTotalTimeoutConstant = 100;
tmouts.WriteTotalTimeoutConstant = 100;
tmouts.WriteTotalTimeoutMultiplier = 100;
SetCommTimeouts(m_hPort, &tmouts);
//设定通讯端口通讯参数
DCB dcb;
bool bol = true;
bol = GetCommState(m_hPort, &dcb);
//配置串口
bol = SetCommState(m_hPort, &dcb);
// 清除通讯端口缓存
PurgeComm(m_hPort,PURGE_TXCLEAR|PURGE_RXCLEAR|PURGE_TXABORT|PURGE_RXABORT);
// 初始化重叠IO对象
OVERLAPPED m_OverlappedRead;
OVERLAPPED m_OverlappedWrite;
HANDLE m_hStopCommEvent;
HANDLE m_hDataReady;
memset(&m_OverlappedRead, 0, sizeof(OVERLAPPED));
m_OverlappedRead.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
memset(&m_OverlappedWrite, 0, sizeof(OVERLAPPED));
m_OverlappedWrite.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
// 初始化事件对象
m_hStopCommEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
m_hDataReady = CreateEvent(NULL, FALSE, FALSE, NULL);
//初始化
DWORD iBytesLength;
char chInitCode[] = "\x0D\x1B\x40";
if(!WriteFile(m_hPort, chInitCode, (DWORD)3L, &iBytesLength, NULL))
{
p_sErrMsg = "初始化失败";
return false;
}
}
return true;
}
//向设备写数据
int USBPrinter::WriteData(QString p_sInput)
{
DWORD dwWrite;
string sInput = p_sInput.toLocal8Bit().data();
return WriteFile(m_hPort, sInput.c_str(), (DWORD)sInput.length(), &dwWrite, NULL);
}
bool USBPrinter::ClosePort()
{
CloseHandle(m_hPort);//关闭端口
return true;
}
测试一下USB设备信息获取功能
QStringList sUSBDeviceList;
QString sError;
GetDevicePath(sUSBDeviceList, sError);
for(int i = 0; i < sUSBDeviceList.size(); i++)
{
qDebug() << sUSBDeviceList[i];
}
打印内容
"\\\\?\\usb#vid_5986&pid_2113#5&21cd2d89&0&6#{a5dcbf10-6530-11d2-901f-00c04fb951ed}"
"\\\\?\\usb#vid_8087&pid_0aaa#5&21cd2d89&0&14#{a5dcbf10-6530-11d2-901f-00c04fb951ed}"
"\\\\?\\usb#vid_258a&pid_1007#5&21cd2d89&0&3#{a5dcbf10-6530-11d2-901f-00c04fb951ed}"
"\\\\?\\usb#vid_0c45&pid_7650#5&21cd2d89&0&2#{a5dcbf10-6530-11d2-901f-00c04fb951ed}"
过滤设备类型
//打印fromWCharArray(buf)即可知道设备类型,
QString::fromWCharArray(buf);
//打印内容如下
"USB Composite Device"
"英特尔(R) 无线 Bluetooth(R)"
"USB Composite Device"
"USB Composite Device"
//过滤指定设备类型
if("英特尔(R) 无线 Bluetooth(R)" != QString::fromWCharArray(buf))
continue;