最近在写一个程序,需要检测USB设备热拔插事件。百度了一下需要响应 WM_DEVICECHANGE这个消息。
响应函数申明:
afx_msg BOOL OnDeviceChange(WPARAM nEventType, DWORD dwData);
消息映射:
BEGIN_MESSAGE_MAP(CPadSkipDlg, CDialog)
//{{AFX_MSG_MAP(CPadSkipDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_CBN_SELCHANGE(IDC_COMBO_ROW, OnSelchangeComboRow)
ON_CBN_SELCHANGE(IDC_COMBO_COL, OnSelchangeComboCol)
ON_WM_SIZE()
ON_BN_CLICKED(IDC_BTN_START, OnBtnStart)
ON_COMMAND(ID_MENU_CONFIG, OnMenuConfig)
ON_COMMAND(ID_MENU_DRAW, OnMenuDraw)
ON_COMMAND(ID_MENU_INT, OnMenuInt)
ON_COMMAND(ID_MENU_TURN, OnMenuTurn)
ON_BN_CLICKED(IDC_BTN_UPDATE_FRAME, OnBtnUpdateFrame)
ON_WM_TIMER()
ON_WM_DEVICECHANGE()
ON_MESSAGE(WM_STOP_READ, OnStopRead)
ON_CBN_SELENDCANCEL(IDC_COMBO_COL, OnSelendcancelComboCol)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
响应函数实现:
BOOL CPadSkipDlg::OnDeviceChange(WPARAM nEventType, DWORD dwData)
{
PDEV_BROADCAST_DEVICEINTERFACE pdbi;
CString szDevPathName;
CString szFindDevPath;
//dwData是一个指向DEV_BROADCAST_DEVICEINTERFACE结构体的指针,
//在该结构体中保存了设备的类型、路径名等参数。通过跟我们指定设备
//的路径名比较,即可以判断是否是我们指定的设备拔下或者插入了。
pdbi=(PDEV_BROADCAST_DEVICEINTERFACE)dwData;
szFindDevPath.Format(_T("VID_%04x&PID_%04x"), m_dwVentorID, m_dwProductID);
switch(nEventType) //参数nEventType中保存着事件的类型
{
//设备连接事件
case DBT_DEVICEARRIVAL:
if(pdbi->dbcc_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
{
szDevPathName = pdbi->dbcc_name; //保存发生状态改变的设备的路径名
int nIndex1 = szDevPathName.Find(szFindDevPath, 7);
if (nIndex1 != -1)
{
assert(!m_I2CmdObject.IsOpen());
m_bUsbDevFound = TRUE;
m_I2CmdObject.Open(m_dwVentorID, m_dwProductID);
m_StatBar.SetPaneText(0, _T("HID设备连接成功"));
}
}
return 1;
//设备拔出事件
case DBT_DEVICEREMOVECOMPLETE:
if(pdbi->dbcc_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
{
szDevPathName = pdbi->dbcc_name; //保存发生状态改变的设备的路径名
int nIndex1 = szDevPathName.Find(szFindDevPath, 7);
if (nIndex1 != -1)
{
assert(m_I2CmdObject.IsOpen());
m_bUsbDevFound = FALSE;
m_I2CmdObject.Close();
m_StatBar.SetPaneText(0, _T("HID设备连接失败"));
}
}
return 1;
default:
return 1;
}
}
OnDeviceChange函数的确响应了,但是nEventType一直为7,查了一下msdn。发现为DBT_DEVICECHANGED。很奇怪,于是百度了一下,发现需要注册设备事件,注册函数如下:
BOOL CPadSkipDlg::RegisterDevice()
{
GUID HidGuid;
HDEVNOTIFY hDeviceNotify;
// mark,这里guid一定要选正确,不然此类设备找不到
HidD_GetHidGuid(&HidGuid);
DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;
ZeroMemory( &NotificationFilter, sizeof(NotificationFilter) );
NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
NotificationFilter.dbcc_classguid = HidGuid;
hDeviceNotify = RegisterDeviceNotification(
m_hWnd, // events recipient
&NotificationFilter, // type of device
DEVICE_NOTIFY_WINDOW_HANDLE // type of recipient handle
);
if ( NULL == hDeviceNotify )
{
return FALSE;
}
return TRUE;
}
问题得到圆满解决。