C++ 在我的Qt应用程序中接收到WM_DEVICECHANGE,但未接收到DBT_DEVICEARRIVAL

C++ 在我的Qt应用程序中接收到WM_DEVICECHANGE,但未接收到DBT_DEVICEARRIVAL,c++,qt,C++,Qt,下面是一个在Windows7中检测USB闪存驱动器插件和插件检测的示例。我确实收到了通知WM_DEVICECHANGE,但没有收到插入USB设备时发出的通知DBT_DEVICEARRIVAL。我的代码如下: /******************************************* * WINDOWS EVENTS ********************************************/ /*We use the first WM_PAIN

下面是一个在Windows7中检测USB闪存驱动器插件和插件检测的示例。我确实收到了通知
WM_DEVICECHANGE
,但没有收到插入USB设备时发出的通知
DBT_DEVICEARRIVAL
。我的代码如下:

/*******************************************
*             WINDOWS EVENTS
********************************************/
/*We use the first WM_PAINT event to get the handle of main window
  and pass it to RegisterDeviceNotification function.
  It not possible to do this in the contructor because the
  main window does not exist yet.
  WM_DEVICECHANGE event notify us that a device is attached or detached */
bool USBexample::nativeEvent(const QByteArray & eventType, void * message, long * result)
{
    MSG * msg = static_cast< MSG * > (message);
    int msgType = msg->message;
    if(msgType == WM_PAINT)
    {
        if(!msgp)   //Only the first WM_PAINT
        {
            GUID InterfaceClassGuid = HID_CLASSGUID;
            DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;
            ZeroMemory( &NotificationFilter, sizeof(NotificationFilter) );
            NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
            NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
            NotificationFilter.dbcc_classguid = InterfaceClassGuid;
            HWND hw = (HWND) this->effectiveWinId();   //Main window handle
            hDevNotify = RegisterDeviceNotification(hw,&NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE);
            msgp = true;
        }
    }
    if(msgType == WM_DEVICECHANGE)
    {
       qDebug() << "WM_DEVICECHANGE recieved";
       PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)msg->lParam;
       switch(msg->wParam)
       {
             case DBT_DEVICEARRIVAL: // never comes here!
                if (lpdb -> dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
                {

                    qDebug() << "DBT_DEVICEARRIVAL case";

                    PDEV_BROADCAST_DEVICEINTERFACE lpdbv = (PDEV_BROADCAST_DEVICEINTERFACE)lpdb;
                    int i = 0;
                    QString s;
                    //to find a better way for this...
                    while(lpdbv->dbcc_name[i] != 0)
                    {
                        s.append(lpdbv->dbcc_name[i]);
                        i++;
                    }
                    s = s.toUpper();
                    if(s.contains(MY_DEVICE_VIDPID))
                        emit USB_Arrived();
                }
            break;
            case DBT_DEVICEREMOVECOMPLETE:
                if (lpdb -> dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
                {
                    qDebug() << "DBT_DEVICEREMOVECOMPLETE case";

                    PDEV_BROADCAST_DEVICEINTERFACE lpdbv = (PDEV_BROADCAST_DEVICEINTERFACE)lpdb;
                    int i = 0;
                    QString s;
                    //to find a better way for this...
                    while(lpdbv->dbcc_name[i] != 0)
                    {
                        s.append(lpdbv->dbcc_name[i]);
                        i++;
                    }
                    s = s.toUpper();
                    if(s.contains(MY_DEVICE_VIDPID))
                        emit USB_Removed();
                }
            break;
       case DBT_DEVICEREMOVEPENDING :
       {
           qDebug() << "DBT_DEVICEREMOVEPENDING case";
       }
       break;
       default:
       {
           qDebug() << "Went to Default case";
       }


       }
    }
    return false;
}
/*******************************************
*WINDOWS事件
********************************************/
/*我们使用第一个WM_PAINT事件来获取主窗口的句柄
并将其传递给RegisterDeviceNotification函数。
在构造函数中不可能执行此操作,因为
主窗口尚不存在。
WM_DEVICECHANGE事件通知我们设备已连接或断开*/
bool USBexample::nativeEvent(常量QByteArray和事件类型、void*消息、long*结果)
{
MSG*MSG=static_cast(消息);
int msgType=msg->message;
if(msgType==WM_油漆)
{
if(!msgp)//仅第一个WM_绘制
{
GUID InterfaceClassGuid=HID\u类GUID;
开发广播设备接口通知过滤器;
零内存(&NotificationFilter,sizeof(NotificationFilter));
NotificationFilter.dbcc_size=sizeof(设备接口);
NotificationFilter.dbcc_devicetype=DBT_DEVTYP_DEVICEINTERFACE;
NotificationFilter.dbcc_classguid=InterfaceClassGuid;
HWND hw=(HWND)this->effectiveWinId();//主窗口句柄
hDevNotify=注册表设备化(硬件、通知过滤器、设备通知窗口句柄);
msgp=真;
}
}
if(msgType==WM_设备更改)
{
qDebug()内存;
开关(msg->wParam)
{
case DBT_DEVICEARRIVAL://永远不会来这里!
if(lpdb->dbch\u设备类型==DBT\u DEVTYP\u设备接口)
{
qDebug()dbcc_名称[i]!=0)
{
s、 追加(lpdbv->dbcc_name[i]);
i++;
}
s=s.toUpper();
如果(s.包含(我的设备)
发出USB_到达();
}
打破
案例DBT_设备移动完成:
if(lpdb->dbch\u设备类型==DBT\u DEVTYP\u设备接口)
{
qDebug()dbcc_名称[i]!=0)
{
s、 追加(lpdbv->dbcc_name[i]);
i++;
}
s=s.toUpper();
如果(s.包含(我的设备)
发射USB_已移除();
}
打破
案件DBT_设备移动未决:
{

qDebug()我发现了这一点,如果其他人遇到类似问题,这里是解决方案

问题是下一行中的
InterfaceClassGuid

GUID InterfaceClassGuid = HID_CLASSGUID;
HID\u CLASSGUID
在我的代码中设置为以下值:

#define HID_CLASSGUID {0x4d1e55b2, 0xf16f, 0x11cf,{ 0x88, 0xcb, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30}}
这是错误的,我从示例中选择了它,但从未意识到我需要更改它。有不同的值可注册不同类型的通知,并且帮助系统在这种情况下没有太大帮助,但下面是有效GUID的列表

我将其更改为以下内容,现在我得到了所需的通知

#define HID_CLASSGUID  {0x745a17a0,0x74d3, 0x11d0, 0xb6fe, 0x00a0c90f57da}

此问题的另一个可能原因可能是传递给RegisterDeviceNotification(…)调用的窗口句柄不正确

错误代码:

  QMainWindow w;
  ...
  HANDLE windowId = w.window()->winId();
  RegisterDeviceNotification(&windowId,&NotificationFilter,DEVICE_NOTIFY_WINDOW_HANDLE);
我为winId的地址传递了错误的值,虽然检测到设备的插入和删除,但wparam的值始终为7。 在我将其更改为使用窗口句柄的正确地址后,我将其传递给RegisterDeviceNotification调用,它就工作了。 正确代码:

 QMainWindow w;
 ...
 HANDLE *windowId = (HANDLE *)w.window()->winId();
 RegisterDeviceNotification(windowId,&NotificationFilter,DEVICE_NOTIFY_WINDOW_HANDLE);

我想到的唯一一件事是这样一个花絮:“我们建议您不要存储此值,因为它可能在运行时更改。”检查
effectiveWinId
是否保持不变。如果它发生变化,您需要重新注册。但是消息确实出现在窗口中,只是消息的子部分没有出现。我做的一件事是键入
effectiveWinId()
HWND
否则编译器会抱怨它不能将
WId
转换到
HWND
,不知道这是否能对它做些什么!但我如何编译它,而不是不进行类型转换?