监测串口插拔原理:当设备被插入/拔出的时候,windows会向每个窗体发送WM_DEVICECHANGE消息,当消息的wParam 值等于 DBT_DEVICEARRIVAL时,表示设备被插入并且已经可用;如果wParam值等于DBT_DEVICEREMOVECOMPLETE,表示设备已经被移出。它们的lParam都指向一个 _DEV_BROADCAST_HDR 结构体(该结构体位于dbt.h头文件中):
struct _DEV_BROADCAST_HDR { /* */
DWORD dbch_size;
DWORD dbch_devicetype;
DWORD dbch_reserved;
};
我们还需要区别设备类型,结构体_DEV_BROADCAST_HDR的成员dbch_devicetype指的是设备类型,在dbt.h头文件中发现有如下设备类型:
...
#define DBT_DEVTYP_OEM 0x00000000 // oem-defined device type
#define DBT_DEVTYP_DEVNODE 0x00000001 // devnode number
#define DBT_DEVTYP_VOLUME 0x00000002 // logical volume
#define DBT_DEVTYP_PORT 0x00000003 // serial, parallel
#define DBT_DEVTYP_NET 0x00000004 // network resource
#if(WINVER >= 0x040A)
#define DBT_DEVTYP_DEVICEINTERFACE 0x00000005 // device interface class
#define DBT_DEVTYP_HANDLE 0x00000006 // file system handle
#endif /* WINVER >= 0x040A */
#if(WINVER >= _WIN32_WINNT_WIN7)
#define DBT_DEVTYP_DEVINST 0x00000007 // device instance
...
当有串口插拔时,dbch_devicetype成员变量就是DBT_DEVTYP_PORT宏定义的值。
我们还需要知道插拔串口的一些信息,比如串口名,定义在_DEV_BROADCAST_PORT_A或_DEV_BROADCAST_PORT_W结构体中,可以根据程序的编码选择相对应的结构体,如下:
typedef struct _DEV_BROADCAST_PORT_A {
DWORD dbcp_size;
DWORD dbcp_devicetype;
DWORD dbcp_reserved;
char dbcp_name[1]; // 串口名
} DEV_BROADCAST_PORT_A, *PDEV_BROADCAST_PORT_A;
typedef struct _DEV_BROADCAST_PORT_W {
DWORD dbcp_size;
DWORD dbcp_devicetype;
DWORD dbcp_reserved;
wchar_t dbcp_name[1]; // 串口名
} DEV_BROADCAST_PORT_W, DBTFAR *PDEV_BROADCAST_PORT_W;
#ifdef UNICODE
typedef DEV_BROADCAST_PORT_W DEV_BROADCAST_PORT;
typedef PDEV_BROADCAST_PORT_W PDEV_BROADCAST_PORT;
#else
typedef DEV_BROADCAST_PORT_A DEV_BROADCAST_PORT;
typedef PDEV_BROADCAST_PORT_A PDEV_BROADCAST_PORT;
#endif
结合duilib的消息机制,我这里是公有继承WindowImplBase类,重写HandleCustomMessage函数。
部分实现代码
LRESULT CMainWnd::HandleCustomMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
switch (uMsg)
{
case WM_DEVICECHANGE:
{
PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)lParam;
switch (wParam)
{
/*
** 串口插入
*/
case DBT_DEVICEARRIVAL:
{
/*
** 如果插入的设备类型是串口
*/
if (lpdb->dbch_devicetype == DBT_DEVTYP_PORT)
{
PDEV_BROADCAST_PORT lpdbv = (PDEV_BROADCAST_PORT)lpdb;
/*
** 获取串口名
*/
CDuiString strPortName = lpdbv->dbcp_name;
CDuiString strTipValue = _T("串口号 ");
strPortName = strTipValue + strPortName;
strPortName = strPortName + _T(" 被插入");
/*
** 以提示框的形式显示
*/
CMsgBoxWnd::MsgBox(GetHWND(), _T("提示"), strPortName);
}
}
break;
/*
** 串口拔出
*/
case DBT_DEVICEREMOVECOMPLETE:
{
/*
** 如果被拔出的设备类型是串口
*/
if (lpdb->dbch_devicetype == DBT_DEVTYP_PORT)
{
PDEV_BROADCAST_PORT lpdbv = (PDEV_BROADCAST_PORT)lpdb;
/*
** 获取串口名
*/
CDuiString strPortName = lpdbv->dbcp_name;
CDuiString strTipValue = _T("串口号 ");
strPortName = strTipValue + strPortName;
strPortName = strPortName + _T(" 被拔出");
/*
** 以提示框的形式显示
*/
CMsgBoxWnd::MsgBox(GetHWND(), _T("提示"), strPortName);
}
}
break;
case DBT_DEVNODES_CHANGED:
break;
default:
break;
}
}
break;
default:
break;
}
return __super::HandleCustomMessage(uMsg, wParam, lParam, bHandled);
}
运行,看效果,串口设备插入的时候:
串口设备拔出的时候:
本人水平有限,如有错误,麻烦指出。