最近在寫一個程序,需要檢測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;
}
問題得到圓滿解決。