// Windows应用程序都是基于消息/事件驱动的,任何一个窗口都能接收消息,并对该消息作出相应的处理。
// U盘等移动设备的插入或者移除操作有与之对应的消息-WM_DEVICECHANGE。实现监控U盘的插入和拔出,只需要捕获这个消息并对它进行处理即可实现。
// PS:WindowProc函数:
// 功能:消息处理回调函数。
// 原型:LRESULT CALLBACK WindowProc (
// HWND hwnd,
// UINT uMsg,
// WPARAM wParam,
// LPARAM lParam
// )
// 参数:hwnd:指定窗口的句柄。
// uMsg:消息ID,是一个枚举值,这里是WM_DEVICECHANGE.
// wParam:消息附带的参数,改参数可以是Dbt.h头文件中的以下值之一:
// DBT_CONFIGCHANGECANCELED:更改当前配置(插入或移除)的请求已取消。
// DBT_CONFIGCHAGED:由于插入或移除,当前配置已更改。
// DBT_CUSTOMLEVEL:发生了自定义事件。
// DBT_DEVICEARRIVAL:已插入了设备或介质,现在可以使用它。
// DBT_DEVICEQUERYREMOVE:请求删除设备或介质的权限。
// DBT_DEVICEREMOVECOMPLETE:已删除设备或介质。
// DBT_DEVICEREMOVEPENDING:即将删除一个介质或设备。
// DBT_DEVICETYPESPECIFIC:设备发生特定事件。
// DBT_DEVNODES_CHANGED:已将设备添加到系统或从系统中删除。
// DBT_QUERYCHANGECONFIG:请求权限更改当前配置。
// DBT_USERDEFINED:此消息的含义是由用户自己定义。
// lParam:指向由事件特定的数据结构的指针。其格式取决于wParam参数的值。
// 结果:若返回TRUE表示授予请求。若返回BROADCAST_QUERY_DENY表示拒绝该请求。
// PS:监控U盘插入或删除,wParam应当为DBT_DEVICEREMOVECOMPLETE和DBT_DEVICEARRIVAL两个。
// PS:DEV_BROADCAST_HDR结构:
// 定义:typedef struct _DEV_BROADCAST_HDR {
// DWORD dbch_size;
// DWORD dbch_devicetype;
// DWORD dbch_reserved;
// } DEV_BROADCAST_HDR, *PDEV_BROADCAST_HDR;
// 成员:dbch_size:指向这个结构的代销。如果这是由用户自定义的事件,则该成员必须是此标头的大小加上DEV_BROADCAST_USERDEFINED结构中的可变长度数据的大小。
// dbch_devicetype:指定设备类型,确定前三个成员之后的事件特定信息。为以下值之一:
// DBT_DEVTYP_DEVICEINTERFACE:设备类,对应DEV_BROADCAST_DEVICEINTERFACE结构。
// DBT_DEVTYP_HANDLE:文件系统句柄,对应DEV_BROADCAST_HANDLE结构。
// DBT_DEVTYP_OEM:OEM或IHV定义的设备类型,对应DEV_BROADCAST_OEM结构。
// DBT_DEVTYP_PORT:端口设备,对应DEV_BROADCAST_PROT结构。
// DBT_DEVTYP_VOLUME:逻辑卷,对应DEV_BROADCAST_VOLUME结构。
// dbch_reserved:保留。
// PS:DEV_BROADCAST_VOLUME结构:
// 定义:typedef struct _DEV_BROADCAST_VOLUME {
// DWORD dbcv_size;
// DWORD dbcv_devicetype;
// DWORD dbcv_reservced;
// DWORD dbcv_unitmask;
// WORD dbcv_flags;
// } DEV_BROADCAST_VOLUME, *PDEV_BROADCAST_VOLUME;
// 参数:前面三个成员和DEV_BROADCAST_HDR相同。
// dbcv_unitmask:标识一个或多个逻辑单元的位源码。掩码中的每位对应于一个逻辑驱动器。位0标识驱动器A,位1标识驱动器B,以此类推。
// dbcv_flags:DBTF_MEDIA:更改影响驱动器的介质。DBTF_NET:指示逻辑卷是一个网络卷。
// PS:实现原理:
// 在消息回调函数WindowProc中拦截设备操作对应的消息WM_DEVICECHANGE,再判断wparam参数的类型,如果是DBT_DEVICEARRIVAL表示设备插入成功,
// 如果是DBT_DEVICEREMOVECOMPLETE表示设备移除成功。先将lparam转为DBT_BROADCAST_HDR,去其成员dbcv_deivcetype,U判断操作对应DEV_BROADCAST_VOLUME,
// 然后再讲lparam转变为DEV_BROADCAST_VOLUME结构体,获取成员dbcv_unitmask,这是一个位掩码,使用for循环来对它的每一位检测,其位上为1在获取到其盘符。
// 示例代码:
BEGIN_MESSAGE_MAP(...)
ON_MESSAGE(WM_DEVICECHANGE, OnDeviceChange)
END_MESSAGE_MAP()
LRESULT OnDeviceChange(WPARAM wParam, LPARAM lParam)
{
switch (wParam)
{
// 设备已插入
case DBT_DEVICEARRIVAL:
// 设备已移除
case DBT_DEVICEREMOVECOMPLETE:
{
// 转换结构体
PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)lParam;
// 逻辑卷
if (DBT_DEVTYP_VOLUME == lpdb.dbcv_devicetype)
{
// 根据decv_unitmask计算出设备盘符
PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb;
DWORD dwDriverMask = lpdbv->dbcv_unitmask;
DWORD dwTemp = 1;
char szDriver[4] = "A:\";
for (szDriver[0] == 'A'; szDriver[0] <= 'Z'; ++szDriver[0])
{
if (0 < dwTemp & dwDriverMask)
{
// 获取设备盘符
::MessageBox(NULL, szDriver, "设备已插入", MB_OK);
// MessageBox(NULL, szDriver, "设备已移除", MB_OK);
}
// 移位操作
dwTemp = (dwTemp << 1);
}
}
}
break;
default:
break;
}
}