当设备被插入/拔出的时候,WINDOWS会向每个窗体发送WM_DEVICECHANGE 消息,当消息的wParam 值等于 DBT_DEVICEARRIVAL 时,表示Media设备被插入并且已经可用;如果wParam值等于DBT_DEVICEREMOVECOMPLETE,表示Media设备已经被移出。
它们的lParam都指向一个 DEV_BROADCAST_HDR结构体,其原形如下:
struct _DEV_BROADCAST_HDR { /* */
DWORD dbch_size;
DWORD dbch_devicetype;
DWORD dbch_reserved;
};
这个结构体仅仅是一个“头”(HDR),其后还有附加数据,dbch_size表示结构体实例的字节数,当其中的dbch_devicetype字段值等于DBT_DEVTYP_VOLUME时,表示当前设备是逻辑驱动器,且lParam实际上指向的应该是DEV_BROADCAST_VOLUME 结构体实例(真佩服这种逻辑),DEV_BROADCAST_VOLUME 结构体原形如下:
struct _DEV_BROADCAST_VOLUME { /* */
DWORD dbcv_size;
DWORD dbcv_devicetype;
DWORD dbcv_reserved;
DWORD dbcv_unitmask;
WORD dbcv_flags;
};
其中dbcv_unitmask 字段表示当前改变的驱动器掩码,第一位表示驱动器号A,第二位表示驱动器号B,第三位表示驱动器号C,以此类推…… dbcv_flags 表示驱动器的类别,如果等于1,则是光盘驱动器;如果是2,则是网络驱动器;如果是硬盘、U盘则都等于0
所以,我只需要在程序中捕捉WM_DEVICECHANGE 消息,然后根据具体情况去处理即可。
下面看我的一段重载WndProc处理WM_DEVICECHANGE的过程。。
void __fastcall TMainForm::WndProc(TMessage &Message)
{
if( wFlag == TRUE)
{
if(Message.Msg == WM_DEVICECHANGE)
{
switch (Message.WParam)
{
case DBT_DEVICEARRIVAL:
{
PDEV_BROADCAST_HDR pstDevHdr = (PDEV_BROADCAST_HDR)Message.LParam;
if(pstDevHdr->dbch_devicetype == DBT_DEVTYP_VOLUME)
{
PDEV_BROADCAST_VOLUME pstDev = (PDEV_BROADCAST_VOLUME)Message.LParam;
if(pstDev->dbcv_flags == 0)
{
mmoMonLog->Lines->Add("USB设备插入");
mmoMonLog->Lines->Add("当前USB盘符为" + AnsiString(ScanUsbDisk())+"盘");
}
}
}
break;
case DBT_DEVICEREMOVECOMPLETE:
{
mmoMonLog->Lines->Add("USB设备移除");
}
break;
default:
break;
}
}
}
TForm::WndProc(Message);
}