本次分享一中检测设备热插拔的方法,比如,在系统中插入一个usb设备,无线网卡等,都可以检测到,并决定后续的工作;研究检测计算机硬件的拔插,包括某类设备接口、文件系统、OEM或IHV厂商自定义设定的设备、端El设备(串行或并行)、逻辑磁盘盘卷;常用设备接口类GUID,根据需要进行注册;主要用到WM_DEVICECHANGE消息,框架调用这个函数来通知应用程序或者设备驱动程序设备硬件配置或者电脑的配置被改变了,此消息只有顶层窗体(CWnd)的程序才能收到这个消息;仅仅串口、磁盘发生改变,才对每个程序广播这个消息,所以必须调用RegisterDeviceNotification()API来注册其他类型的设备改变,或是你的程序仅仅是一个服务程序、没有顶层窗体的程序。
1.添加消息处理函数:
afx_msg BOOL OnDeviceChange( UINT nEventType, DWORD dwData );
2.消息映射:
BEGIN_MESSAGE_MAP(OGrgFrmRepair, CDialog)
ON_WM_DEVICECHANGE()
END_MESSAGE_MAP()
1.在OnInitDialog()中注册设备类型的接口
//注册一个设备类型的接口
static const GUID GUID_DEVINTERFACE_LIST[] =
{
//GUID_DEVINTERFACE_MOUSE,
//GUID_DEVINTERFACE_KEYBOARD
{ 0X378DE44C, 0X56EF, 0X11D1, { 0XBC,0X8C,0X00,0XA0,0XC9,0X14,0X05,0XDD}},
{ 0X884B96C3, 0X56EF, 0X11D1, { 0XBC,0X8C,0X00,0XA0,0XC9,0X14,0X05,0XDD}}
};
HDEVNOTIFY hDevNotify;
DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;
ZeroMemory(&NotificationFilter, sizeof(NotificationFilter));
NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
for (int i = 0; iGetSafeHwnd(), &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE);
if (!hDevNotify)
{
AfxMessageBox(CString("Can't register device notification: ")
+ _com_error(GetLastError()).ErrorMessage(), MB_ICONEXCLAMATION);
return FALSE;
}
}
2.实现OnDeviceChange(UINT nEventType, DWORD_PTR dwData)函数
其中用到了MessageBoxTimeOut,这个函数和MessageBox一样,但是可以设置其显示的时间,到时间后自动关闭,需要加入下面代码可支持使用;用这个只是为了测试,在实际的项目开发中,检测到拔插之后,加入你想要进行的操作代码即可。
//为支持MessageBoxTimeOut
extern "C"
{
int WINAPI MessageBoxTimeoutA(IN HWND hWnd, IN LPCSTR lpText, IN LPCSTR lpCaption, IN UINT uType, IN WORD wLanguageId, IN DWORD dwMilliseconds);
int WINAPI MessageBoxTimeoutW(IN HWND hWnd, IN LPCWSTR lpText, IN LPCWSTR lpCaption, IN UINT uType, IN WORD wLanguageId, IN DWORD dwMilliseconds);
};
#ifdef UNICODE
#define MessageBoxTimeout MessageBoxTimeoutW
#else
#define MessageBoxTimeout MessageBoxTimeoutA
#endif
BOOL CDeviceChangeDlg::OnDeviceChange(UINT nEventType, DWORD_PTR dwData)
{
CString Msg;
PDEV_BROADCAST_HDR pHdr = (PDEV_BROADCAST_HDR)dwData;
switch (nEventType)
{
case DBT_DEVICEREMOVECOMPLETE://移除设备
{
switch (pHdr->dbch_devicetype)
{
case DBT_DEVTYP_DEVICEINTERFACE:
{
PDEV_BROADCAST_DEVICEINTERFACE pDevInf = (PDEV_BROADCAST_DEVICEINTERFACE)pHdr;
if (pDevInf->dbcc_classguid == GUID_DEVINTERFACE_MOUSE)
{
MessageBoxTimeout(NULL, _T("鼠标已拔出"), _T("提示"), MB_OK, 0, 1000);
//::MessageBox(NULL, _T("鼠标已拔出"), _T("提示"), MB_ICONINFORMATION | MB_OK);
}
else if (pDevInf->dbcc_classguid == GUID_DEVINTERFACE_KEYBOARD)
{
MessageBoxTimeout(NULL, _T("键盘已拔出"), _T("提示"), MB_OK, 0, 1000);
//::MessageBox(NULL, _T("键盘已拔出"), _T("提示"), MB_ICONINFORMATION | MB_OK);
}
}
break;
case DBT_DEVTYP_VOLUME:
{
PDEV_BROADCAST_VOLUME pDevVolume = (PDEV_BROADCAST_VOLUME)pHdr;
switch (pDevVolume->dbcv_flags)
{
case 0://U盘
{
CString strDriver;
strDriver= FirstDriveFromMask(pDevVolume->dbcv_unitmask);
Msg.Format(_T("%s盘拔出!"), strDriver.GetBuffer(0));
m_Edit.SetWindowText(Msg);//m_Edit为一个CEdit类型的变量,是为了方便测试界面上加了一个Edit,绑定了控件类型的变量
}
break;
case DBTF_MEDIA: //光盘
break;
}
}
break;
}
}
break;
case DBT_DEVICEARRIVAL://添加设备
{
switch (pHdr->dbch_devicetype)
{
case DBT_DEVTYP_DEVICEINTERFACE:
{
PDEV_BROADCAST_DEVICEINTERFACE pDevInf = (PDEV_BROADCAST_DEVICEINTERFACE)pHdr;
if (pDevInf->dbcc_classguid == GUID_DEVINTERFACE_MOUSE)
{
MessageBoxTimeout(NULL,_T("鼠标已插入"), _T("提示"), MB_OK, 0, 1000);
//::MessageBox(NULL, _T("鼠标已插入"), _T("提示"), MB_ICONINFORMATION | MB_OK);
}
else if (pDevInf->dbcc_classguid == GUID_DEVINTERFACE_KEYBOARD)
{
MessageBoxTimeout(NULL, _T("键盘已插入"), _T("提示"), MB_OK, 0, 1000);
//::MessageBox(NULL, _T("键盘已插入"), _T("提示"), MB_ICONINFORMATION | MB_OK);
}
}
break;
case DBT_DEVTYP_VOLUME:
{
PDEV_BROADCAST_VOLUME pDevVolume = (PDEV_BROADCAST_VOLUME)pHdr;
switch (pDevVolume->dbcv_flags)
{
case 0://U盘
{
CString strDriver;
strDriver = GetDrive(pDevVolume->dbcv_unitmask);//GetDrive函数功能为获取盘符
Msg.Format(_T("%s盘插入!"), strDriver.GetBuffer(0));
m_Edit.SetWindowText(Msg);
}
break;
case DBTF_MEDIA: //光盘
break;
}
}
break;
}
}
break;
default:
break;
}
return TRUE;
}
char CDeviceChangeDlg::GetDrive(ULONG unitmask) //获取盘符
{
char i;
for (i = 0; i < 26; ++i)
{
if (unitmask & 0x1)
break;
unitmask = unitmask >> 1;
}
return (i + 'A');
}