一、Qt+windows API驱动USB设备——获取USB设备信息列表

Qt驱动USB设备的方法

  1. 找设备厂商要动态库和接口文档;
  2. 找对应USB设备的Qt库,eg:QCamera、QPrinter等
  3. USB转串口,使用QtSerialPort;
  4. 使用第三方QtUSB库(Qt本身没有封装USB的库);
  5. 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;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值