Windows上USB设备检测

14 篇文章 0 订阅

枚举总线

主机控制器的驱动程序(HCD(Host Control Driver))。它位于USB主机控制器与USB系统软件之间。
可以用CreateFile打开名字为" \\\\.\\HCD1",\\\\.\\HCD2的文件来检测HCD总线。
打开句柄之后可以通过 DeviceIoControl 传递IOCTL_GET_HCD_DRIVERKEY_NAME 参数来得到DriveName。
并可以用 CM_系列函数遍历各节点来得到相应的驱动描述。
可以通过调用 IOCTL_USB_GET_ROOT_HUB_NAME 为参数的DeviceIoControl 来得到此主机驱动器上的根HUB。
通过CreateFile打开名字为"\\\\.\\HUBNAME"形式的文件,来得到根HUB的句柄,然后通过将IOCTL_USB_GET_NODE_CONNECTION_INFORMATION 传递给函数DeviceIoControl来得到此HUB的连接信息,通过这个信息可以知道此HUB上有几个端口,以及每个端口的设备连接情况。还能得到连接端口设备的VID,PID,如果有的话。
如果HUB端口已经有设备连接,可以通过DeviceIoControl传递参数IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME 来得到连接设备的情况(传递参数为Hub句柄和当前的索引值,索引值要从1开始),如果当前端口连接的设备为另外一个HUB,那么可以通过像DevioceIoControl传递参数IOCTL_USB_GET_NODE_CONNECTION_NAME 来得到此HUB的名字,然后就可以枚举得到此子HUB的信息了。
 

查找设备

通过PID或者VID或者ClassGUID或者InterfaceGUID,可以得到符合条件的当前设备。
typedef struct _SSDevHandles
{
    DWORD dwDevsCount;
    HDEVINFO hDevInfoSet;
    SP_DEVINFO_DATA *pDevDatas;
} SSDevHandles;
HANDLE STDCALL SSDevGetDevices(IN LPCTSTR lpVid /* = NULL */, IN LPCTSTR lpPID /* = NULL */,
                             IN const GUID* pSetupClassGuid /* = NULL */, IN const GUID* pInterfaceClassGuid /* = NULL */)
{
    SSDevHandles *phDevs = NULL;
    HDEVINFO hDevInfoSet = INVALID_HANDLE_VALUE;
    check_int_begin
    {
        if(lpVid != NULL && _tcslen(lpVid) == 0)
            lpVid = NULL;
        if(lpPID != NULL && _tcslen(lpPID) == 0)
            lpPID = NULL;
        hDevInfoSet = SetupDiCreateDeviceInfoList(pSetupClassGuid, NULL);
        check_int_bool(hDevInfoSet != INVALID_HANDLE_VALUE, SS_RC_NOT_FOUND);
        if(pInterfaceClassGuid == NULL)
            hDevInfoSet = SetupDiGetClassDevsEx(NULL, NULL, NULL,
                DIGCF_ALLCLASSES|DIGCF_DEVICEINTERFACE|DIGCF_PRESENT,
                hDevInfoSet, NULL, NULL);
        else
            hDevInfoSet = SetupDiGetClassDevsEx(pInterfaceClassGuid, NULL, NULL,
                DIGCF_DEVICEINTERFACE|DIGCF_PRESENT,
                hDevInfoSet, NULL, NULL);
        check_int_bool(hDevInfoSet != INVALID_HANDLE_VALUE, SS_RC_NOT_FOUND);
        SP_DEVINFO_DATA dtDevInfo = { sizeof(SP_DEVINFO_DATA) };
        for(DWORD dwMemIdx = 0; ;dwMemIdx++)
        {
            if(!SetupDiEnumDeviceInfo(hDevInfoSet, dwMemIdx, &dtDevInfo))
            {
                if(::GetLastError() == ERROR_NO_MORE_ITEMS)
                {
                    break;
                }
                continue;;
            }
            if(lpVid != NULL || lpPID != NULL)
            {
                TCHAR szInstanceId[MAX_INSTANCE_ID] = {0};
                SetupDiGetDeviceInstanceId(hDevInfoSet, &dtDevInfo, szInstanceId, SS_DIMOF(szInstanceId), NULL);
                if(_tcslen(szInstanceId) <= 0)
                    continue;
                TCHAR szVID[5] = {0}, szPID[5] = {0};
                if(!SSDevUtilGetVIDPID(szInstanceId, szVID, SS_DIMOF(szVID), szPID, SS_DIMOF(szPID)))
                    continue;
                if(lpVid != NULL && _tcsicmp(lpVid, szVID) != 0)
                    continue;
                if(lpPID != NULL && _tcsicmp(lpPID, szPID) != 0)
                    continue;
            }
            DWORD dwCapbilities = 0;
            if(!SetupDiGetDeviceRegistryProperty(hDevInfoSet, &dtDevInfo, SPDRP_CAPABILITIES, NULL,\
                (BYTE*)&dwCapbilities, sizeof(DWORD), NULL))
                continue;
            if(!SS_FLAG_ISSET(dwCapbilities, CM_DEVCAP_REMOVABLE))
                continue;
            if(phDevs == NULL)
            {
                phDevs = (SSDevHandles *)SS_MALLOC(sizeof(SSDevHandles));
                memset(phDevs, 0, sizeof(SSDevHandles));
                phDevs->hDevInfoSet = INVALID_HANDLE_VALUE;
            }
            phDevs->pDevDatas = (SP_DEVINFO_DATA*)SS_REALLOC(phDevs->pDevDatas, (phDevs->dwDevsCount + 1) * sizeof(SP_DEVINFO_DATA));
            MP_ASSERT(phDevs->pDevDatas != NULL);
            phDevs->pDevDatas[phDevs->dwDevsCount] = dtDevInfo;
            phDevs->dwDevsCount++;
        }
    }
    check_int_finally
    {
        if(phDevs != NULL && phDevs->dwDevsCount > 0)
        {
            phDevs->hDevInfoSet = hDevInfoSet;
            hDevInfoSet = INVALID_HANDLE_VALUE;
        }
        if(hDevInfoSet != INVALID_HANDLE_VALUE)
        {
            SetupDiDestroyDeviceInfoList(hDevInfoSet);
            hDevInfoSet = INVALID_HANDLE_VALUE;
        }
    }
    return phDevs;
}
 
并通过setupDi函数SetupDiGetDeviceInstanceIdSetupDiGetDeviceRegistryProperty 来得到设备信息。
 

监控USB设备插拔

注册设备通知事件
HANDLE STDCALL SSPNPRegisterDeviceNotifyToHwnd(IN HWND hWnd)
{
    if(!::IsWindow(hWnd))
        return NULL;
    SSPNPDeviceNotifyHandle *pDeviceHandle = (SSPNPDeviceNotifyHandle *)SS_MALLOC(sizeof(SSPNPDeviceNotifyHandle));
    memset(pDeviceHandle, 0, sizeof(SSPNPDeviceNotifyHandle));
    DEV_BROADCAST_DEVICEINTERFACE NotificationFilter = {0};
    NotificationFilter.dbcc_size = sizeof(NotificationFilter);
    NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
    for(int nIdx=0; nIdx<SS_DIMOF(GUID_DEVINTERFACE_LIST); nIdx++)
    {
        NotificationFilter.dbcc_classguid = GUID_DEVINTERFACE_LIST[nIdx];
        pDeviceHandle->hDevNotifies[pDeviceHandle->nCount++] = ::RegisterDeviceNotification(hWnd,
            &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE);
    }
    if(pDeviceHandle->nCount <= 0)
    {
        SS_FREE(pDeviceHandle);
        pDeviceHandle = NULL;
    }
    return (HANDLE)pDeviceHandle;
}
BOOL STDCALL SSPNPUnregisterDeviceNotify(IN HANDLE hDevNotify)
{
    SSPNPDeviceNotifyHandle *pDeviceHandle = (SSPNPDeviceNotifyHandle *)hDevNotify;
    if(pDeviceHandle == NULL)
        return FALSE;
    for(int nIdx=0; nIdx<SS_DIMOF(GUID_DEVINTERFACE_LIST); nIdx++)
    {
        if(pDeviceHandle->hDevNotifies[nIdx] != NULL)
             UnregisterDeviceNotification(pDeviceHandle->hDevNotifies[nIdx]);
    }
    SS_FREE(pDeviceHandle);
    pDeviceHandle = NULL;
    return TRUE;
}
反注册设备通知事件
BOOL STDCALL SSPNPUnregisterDeviceNotify(IN HANDLE hDevNotify)
{
    SSPNPDeviceNotifyHandle *pDeviceHandle = (SSPNPDeviceNotifyHandle *)hDevNotify;
    if(pDeviceHandle == NULL)
        return FALSE;
    for(int nIdx=0; nIdx<SS_DIMOF(GUID_DEVINTERFACE_LIST); nIdx++)
    {
        if(pDeviceHandle->hDevNotifies[nIdx] != NULL)
             UnregisterDeviceNotification(pDeviceHandle->hDevNotifies[nIdx]);
    }
    SS_FREE(pDeviceHandle);
    pDeviceHandle = NULL;
    return TRUE;
}
事件发生后会像窗口发送 WM_DEVICECHANGE 消息,可以通过检测wParam是否为 DBT_DEVICEARRIVAL 或者 DBT_DEVICEREMOVECOMPLETE 来判断插拔。如果确实是插拔事件,且lParam不为空,则lParam指向一个结构 DEV_BROADCAST_HDR ,通过判断它的域 dbch_devicetype 来判断事件类型,例如
LPCTSTR STDCALL SSDevGetNameOnDeviceNotifyCB(WPARAM wParam, LPARAM lParam)
{
    if(wParam != DBT_DEVICEARRIVAL && wParam != DBT_DEVICEREMOVECOMPLETE)
        return NULL;
    LPCTSTR lpReturnString = NULL;
    DEV_BROADCAST_HDR *pDevBCHdr = (DEV_BROADCAST_HDR *)lParam;
    MP_ASSERT(pDevBCHdr != NULL);
    switch (pDevBCHdr->dbch_devicetype)
    {
    case DBT_DEVTYP_DEVICEINTERFACE:
        {
            DEV_BROADCAST_DEVICEINTERFACE *pDevBCInterface = (DEV_BROADCAST_DEVICEINTERFACE *)lParam;
            lpReturnString = pDevBCInterface->dbcc_name;
        }
        break;
/*
    case DBT_DEVTYP_VOLUME:
        {
            DEV_BROADCAST_VOLUME *pDevBCVolume = (DEV_BROADCAST_VOLUME *)lParam;
            for(int i=0; i<32; i++)
            {
                if(SS_FLAG_ISSET(pDevBCVolume->dbcv_unitmask, 1<<i))
                {
                    //_T('A') + i;
                }
            }
        }
        break;
*/
    default:
        break;
    }
    return lpReturnString;
}
 
DBT_DEVTYP_VOLUME 消息不用注册窗口事件,顶层窗口会自动获得。
 
常用USB设备GUID
// Copy from HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\DeviceClasses
static const GUID GUID_DEVINTERFACE_LIST[] =
{
    // GUID_DEVINTERFACE_USB_DEVICE
    { 0xA5DCBF10, 0x6530, 0x11D2, { 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED } },
    // GUID_DEVINTERFACE_DISK
    { 0x53f56307, 0xb6bf, 0x11d0, { 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b } },
    // GUID_DEVINTERFACE_HID,
    { 0x4D1E55B2, 0xF16F, 0x11CF, { 0x88, 0xCB, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30 } },
    // GUID_NDIS_LAN_CLASS
    { 0xad498944, 0x762f, 0x11d0, { 0x8d, 0xcb, 0x00, 0xc0, 0x4f, 0xc3, 0x35, 0x8c } },
    // GUID_DEVINTERFACE_COMPORT
    { 0x86e0d1e0, 0x8089, 0x11d0, { 0x9c, 0xe4, 0x08, 0x00, 0x3e, 0x30, 0x1f, 0x73 } },
    // GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR
    { 0x4D36E978, 0xE325, 0x11CE, { 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18 } },
    // GUID_DEVINTERFACE_PARALLEL
    { 0x97F76EF0, 0xF883, 0x11D0, { 0xAF, 0x1F, 0x00, 0x00, 0xF8, 0x00, 0x84, 0x5C } },
    // GUID_DEVINTERFACE_PARCLASS
    { 0x811FC6A5, 0xF728, 0x11D0, { 0xA5, 0x37, 0x00, 0x00, 0xF8, 0x75, 0x3E, 0xD1 } },
};
  • 1
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
现在USB设备却很多,因此对USB设备的查找与读写就必不可少了。但是能找到关于USB读写的资料很少。这里使用VC++示范了一些获得USB的信息的方法。 一、枚举USB设备   通过枚举USB控制器->枚举此控制器上的USB HUB->枚举HUB的各个端口->获得设备信息。 枚举控制器: wsprintf(HCName, "\\\\.\\HCD%d", HCNum); hHCDev = CreateFile(HCName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);   计算机上的USB主控制器以HCD1,HCD2等命名。通过控制器名称,使用CCreateFile 打开它。使用DeviceIoControl即可得到其驱动程序名,以及与它连接的HUB的名称。用CCreateFile打开HUB,获得连接信息。再枚举HUB的各个端口即可获得连接的设备信息。 二、枚举HID设备   HID设备是微软定义的标准人机接口规范。比如USB鼠标,USB游戏手柄等。不用查找具体设备的GUID,使用API HidD_GetHidGuid(&guidHID)即可得到GUID。有了GUID通过API SetupDiEnumDeviceInterfaces可获得是否有设备连接。如果此类设备连接通过SetupDiGetDeviceInterfaceDetail获得它的设备路径信息。使用CCreateFile 打开它,通过HidD_GetAttributes获得其基本属性信息。使用DeviceIoControl可以获得更详细的属性。在本代码中如果计算机上插有USB游戏手柄,可获得其信息。但不知道为什么xp下却不能获得USB鼠标的信息。 三 枚举U盘   先用GetDriveType API获得设备的类型,若类型为REMOVABLE(当然有些大容量U盘可能报告为FIXED,那就需要其他方法来确定了),即可能是U盘。用CCreateFile 打开之后,再用IOCTL_STORAGE_QUERY_PROPERTY为参数的DeviceIoControl来获得其属性。 四、结束语   示例工程在winxp+xpDDK+VC6下编译通过。USB设备种类比较多,也比较特殊,不同厂商的硬件不同,控制软件也不尽相同(我想主要是ICTL码不同,也不容易查到)。使得访问USB口的设备不象串口并口那么方便。这个例程只是展示了访问的基本方法。其中还有些问题还没有解决,发出来希望大家解决之后能通知我或者发表出来。 参考了USBPort,USBview等代码,一并致谢。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值