Search code examples
winapimfcusb

USB insertion and removal events are seen as DBT_DEVTYP_VOLUME device types


I am using MFC and win32 to develop and maintain an application that requires knowledge of when USB WM_DEVICECHANGE messages are sent to the message queue. I am told in various posts that in order to receive USB drive events I have to register a listener that expects a DBT_DEVTYP_DEVICEINTERFACE event. Here is how I'm doing that:

HWND hWnd = GetSafeHwnd();
    DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;
    ZeroMemory(&NotificationFilter, sizeof(NotificationFilter));
    NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
    NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
    m_hUsbEventListener = RegisterDeviceNotification(hWnd, &NotificationFilter, DEVICE_NOTIFY_ALL_INTERFACE_CLASSES);
    if (!m_hUsbEventListener) {
        LOG4CPLUS_ERROR(THE_LOGGER, "Failed to register USB event listener. Reports may be unreliable.");
    }

However, when I go to process the WM_DEVICECHANGE I only receive a message from a device with type DBT_DEVTYP_VOLUME, which I didn't expect to receive at all. Here's how I'm managing the messages which is basically lifted straight from the MSDN docs:

PDEV_BROADCAST_HDR pHdr = (PDEV_BROADCAST_HDR)lparam;
    if (pHdr != nullptr) {
        if (pHdr->dbch_devicetype == DBT_DEVTYP_VOLUME) {
            PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)pHdr;
            char driveLetter = FirstDriveFromMask(lpdbv->dbcv_unitmask);
            switch (wPARAM)
            {
            case DBT_DEVICEARRIVAL:
                break;
            case DBT_DEVICEREMOVECOMPLETE:
                break;
            }
        }
        else if (pHdr->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
            PDEV_BROADCAST_DEVICEINTERFACE lpdbv = (PDEV_BROADCAST_DEVICEINTERFACE)pHdr;
            switch (wPARAM)
            {
            case DBT_DEVICEARRIVAL:
                break;
            case DBT_DEVICEREMOVECOMPLETE:
                break;
            }
        }
    }
    return 0L;

I can't find any information as to which physical media hardware has which device type. Any information would be appreciated.

I tried registering a device-specific event listener more or less following the accepted reply to this post: C++ Win32 Not receiving DBT_DEVICEARRIVAL or DBT_DEVICEREMOVECOMPLETE on WM_DEVICECHANGE

I was expecting to receive a message containing a dbch_devicetype of DBT_DEVTYP_DEVICEINTERFACE but instead I got one of type DBT_DEVTYP_VOLUME which I wasn't expected to receive at all for USB media.


Solution

  • I was attempting to instantiate this listener in the constructor for my apps window, so the call to getsafewnd was premature and returned some irrelevant parent window. Moving the creation of the listener to after the window constructor, and getting it's handle with AfxGetApp()->GetMainWnd()->m_hWnd solves this issue.

    As for why I am getting volume notifications for a USB drive which is a DEVINTERFACE device, I believe it has to do with the drive mounter sending that notification when the drive acquires a drive letter, but I'm not sure.