您的位置:首页 > 其它

Windows上USB设备检测

2012-05-12 10:56 302 查看

枚举总线

主机控制器的驱动程序(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函数SetupDiGetDeviceInstanceId ,SetupDiGetDeviceRegistryProperty 来得到设备信息。

监控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 } },
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: