背景描述:

USB设备的即插即用的属性,使得在实际应用中经常会遇到USB设备在程序运行过程中被移除或插入,应用程序需要该事件进行处理。


基于C++ Builder

1.重载WndProc函数

void __fastcall TForm1::WndProc(TMessage &Message)
{
    if(Message.Msg == WM_DEVICECHANGE) //帮助里面有这个消息的详细说明
    {
        if(Message.WParam == DBT_DEVICEARRIVAL)
        {
            Memo1->Lines->Add("发现USB设备插入!");
        }
        else if(Message.WParam == DBT_DEVICEREMOVECOMPLETE)
        {
            Memo1->Lines->Add("USB设备被拔出!");
        }
        else
        {
            Memo1->Lines->Add("WM_DEVICECHANGE");
        }
    }
   
    TForm::WndProc(Message);
}


2.在FormCreat中(或其他合适的地方添加设备注册)

// 这里只是为了得到HID设备的GUID,实际上可以省掉该步骤
typedef __stdcall void(*pGetHidGuid)(GUID* HidGuid);

GUID HidGuid;
pGetHidGuid HidD_GetHidGuid;
HINSTANCE h;

if ((h = LoadLibrary("hid.dll"))==NULL)
{
    return; 
}
HidD_GetHidGuid=(pGetHidGuid)GetProcAddress(h,"HidD_GetHidGuid");
if(HidD_GetHidGuid==NULL)
{
    return;
}
HidD_GetHidGuid(&HidGuid);

// 这里才是注册USB热插拔消息
DEV_BROADCAST_DEVICEINTERFACE DevInt;
memset(&DevInt,0,sizeof(DEV_BROADCAST_DEVICEINTERFACE));
DevInt.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
DevInt.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
DevInt.dbcc_classguid = HidGuid;
    
RegisterDeviceNotification(Handle,&DevInt,DEVICE_NOTIFY_WINDOW_HANDLE);


注意事项:
1,一定要在重载的WndProc结束的时候调用基类的WndProc函数继续处理,否则将影响其他功能;
2.HidD_GetHidGuid需要调用动态链接库hid.dll(系统自带了)来完成;
3.Handle从基类继承来,这里无需关心;
4.需要引用系统定义的头文件dbt.h;
5.不同的设备有不同的GUID,所有的HID设备的GUID相同;
6.这里用HID来做例子,其他设备可以直接指定GUID(如果不指定GUID,则为全部USB设备);


基于VC6.0

1.在框体代码找到中加入BEGIN_MESSAGE_MAP/END_MESSAGE_MAP,并加入一行

BEGIN_MESSAGE_MAP(CMainDlg, CDialog)
 ON_MESSAGE(WM_DEVICECHANGE, OnDeviceChange) 
END_MESSAGE_MAP()

说明:
WM_DEVICECHANGE是Windows定义的设备改变事件,定义在DBT.h中,其值为0x219
OnDeviceChange是用户定义的回调函数.

2.添加回调函数

BOOL CMainDlg::OnDeviceChange(UINT nEventType, DWORD dwData)
{
    ShowInfo("Device Changed");    //显示函数(用户定已定义的,调试用)
    return TRUE;
}

至此,如果有设备插入及移除已经可以通知到窗体了,但只会收到DBT_DEVNODES_CHANGED事件
(通过nEventType == 0x0007),无法得到详细信息;

3.注册设备
在stdafx.h的第1行加入

#define WINVER 0x0500

注意:一定要加在前边,否则编译会出错

在窗体文件初始化函数OnInitDialog(或其他适当的函数中也行)中添加:

GUID HidGuid;
DEV_BROADCAST_DEVICEINTERFACE DevBroadcastDeviceInterface;  
HidD_GetHidGuid(&HidGuid);    //获取HID设备的接口类GUDI
DevBroadcastDeviceInterface.dbcc_size=sizeof(DevBroadcastDeviceInterface); 
DevBroadcastDeviceInterface.dbcc_devicetype=DBT_DEVTYP_DEVICEINTERFACE;
DevBroadcastDeviceInterface.dbcc_classguid=HidGuid;
//注册设备改变时收到通知
RegisterDeviceNotification(m_hWnd,
                          &DevBroadcastDeviceInterface,
                          DEVICE_NOTIFY_WINDOW_HANDLE);


4.修改OnDeviceChange函数

BOOL CAaaDlg::OnDeviceChange(UINT nEventType, DWORD dwData)
{
  if(nEventType == DBT_DEVICEARRIVAL) 
  {
    ShowInfo("设备已插入");
  }
  else if(nEventType == DBT_DEVICEREMOVECOMPLETE)
  {
    ShowInfo("设备已移除");
  }
  return TRUE;
}


5.此时系统可以正常捕获到详细的信息DBT_DEVICEARRIVAL/DBT_DEVICEREMOVECOMPLETE等;
继续修改OnDeviceChange函数,以添加期望功能;

注意事项:
m_hWnd(消息接收窗口的句柄)从基类继承;