0x00 说明
最先在网上copy的代码,能捕获U盘插入的消息,但不能捕获其他USB设备的消息,且无法获取U盘dbcc_name,多次询问度娘后终于找到正确的姿势,通过RegisterDeviceNotification注册DBT_DEVTYP_DEVICEINTERFACE,获取所有USB类设备的通知。
0x01 WM_DEVICECHANGE
查询MSDN[WM_DEVICECHANGE message],当设备或电脑的硬件配置发生改变时,会给每一个顶层窗口发通知,窗口通过WindowPro接收这个消息。WindowPro中的wParam参数告诉我们是具体是发生了什么事件,即设备或电脑的硬件配置发生了怎样的变化;lParam参数包含了一些设备具体的信息(wParam不同,对应的lParam也有一点的变化)。如果有U盘插入(这里为什么说是U盘而不是USB设备将会在后面进行说明),wParam=DBT_DEVICEARRIVAL,lParam中包含了U盘的盘符信息。
有了上述信息,我们可自己创建一个顶层窗口来接WM_DEVICECHANGE消息。首先定义一个WindowPro函数,当message参数为WM_DEVICECHANGE,wParam参数为DBT_DEVICEARRIVAL时,即表示有U盘插入。
定义个一个窗口类,将窗口的处理函数定义为UsbProc。
0x03 Register DBT_DEVTYP_DEVICEINTERFACE
通过上面的代码,能够捕获U盘插入的消息,但却无法捕获到其他类型的USB设备。经过调试,发现只有当pHdr->dbch_devicetype=DBT_DEVTYP_VOLUME时,才会接收到通知。所以上面的代码中用PDEV_BROADCAST_DEVICEINTERFACE结构去格式化lParam就会得到错误的dbcc_classguid和dbcc_name,而用PDEV_BROADCAST_VOLUME则可以获取正确的盘符信息(dbcv_unitmask)。
MSDN[RegisterDeviceNotification]中Remarks部分说明了顶层窗口会收到basic notification,其中就包括了DBT_DEVTYP_VOLUME和DBT_DEVTYP_PORT,其他类型的通知则需要通过RegisterDeviceNotification来注册。RegisterDeviceNotification中第二个参数填入DEV_BROADCAST_DEVICEINTERFACE结构,dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE、dbcc_classguid = GUID_DEVINTERFACE_USB_DEVICE,也可以根据需要换成他常用设备接口类GUID。
修改WindowPro函数
参考资料
CSDN-关于u盘识别(OnDeviceChange方式)的几个问题,请教!
新浪博客-利用服务获取USB设备插拨事件以及获取设备硬件信息