Search code examples
c++winapiwindows-services

Win32 Device Events : Not receiving DBT_DEVTYP_VOLUME on DBT_DEVICEARRIVAL event


What I'm basically trying to do is making a windows service that listens to storage device insertion such as (USB flash drive, external HDD/SSD)... I'm follwing these 2 tutorials :


I got the service part running correctly, I'm also receiving Device Notifications.
But when I try to put a USB flash drive, I receive a notification but dbch_devicetype in PDEV_BROADCAST_HDRis always DBT_DEVTYP_DEVICEINTERFACE never DBT_DEVTYP_VOLUME. Also when I RegisterDeviceNotification with DBT_DEVTYP_VOLUME I don't receive anything. I have been searching for hours and I could't find why I'm not receiving the correct notifications

The function responsible for registering the Service for device notifications :

void Myclassname::registerForDeviceNotifications() {
    DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;
    ZeroMemory(&NotificationFilter, sizeof(NotificationFilter));
    NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
    NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
    NotificationFilter.dbcc_classguid = { 0x71a27cdd, 0x812a, 0x11d0, 0xbe, 0xc7, 0x08, 0x00, 0x2b, 0xe2, 0x09, 0x2f };

    m_hDevNotify = RegisterDeviceNotification(m_statusHandle,
        &NotificationFilter, DEVICE_NOTIFY_SERVICE_HANDLE |
        DEVICE_NOTIFY_ALL_INTERFACE_CLASSES);
}

The function responsible for handling the device notifications :

void AutobackupService::handleDeviceChangeNotif(DWORD dwEventType, LPVOID lpEventData) {
    switch (dwEventType) {
    case DBT_DEVICEREMOVECOMPLETE: {
        PDEV_BROADCAST_HDR eventData = (PDEV_BROADCAST_HDR)lpEventData;
        logToFile(std::to_string(eventData->dbch_devicetype));
        if (eventData->dbch_devicetype == DBT_DEVTYP_VOLUME)
        {
            PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)eventData;
            if (lpdbv->dbcv_flags & DBTF_MEDIA)
            {
                WriteEventLogEntry(L"USB device removed " + lpdbv->dbcv_unitmask, EVENTLOG_INFORMATION_TYPE);
            }
        }
    }
                                   break;
    case DBT_DEVICEARRIVAL: {
        PDEV_BROADCAST_HDR eventData = (PDEV_BROADCAST_HDR)lpEventData;
        logToFile(std::to_string(eventData->dbch_devicetype));
        if (eventData->dbch_devicetype == DBT_DEVTYP_VOLUME)
        {
            PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)eventData;
            if (lpdbv->dbcv_flags & DBTF_MEDIA)
            {
                WriteEventLogEntry(L"USB device removed " + lpdbv->dbcv_unitmask, EVENTLOG_INFORMATION_TYPE);
            }
        }
    }
    }
}

Solution

  • at first your wrong register for volume notification. code must be

            static DEV_BROADCAST_DEVICEINTERFACE NotificationFilter = { 
                sizeof(DEV_BROADCAST_DEVICEINTERFACE), 
                DBT_DEVTYP_DEVICEINTERFACE,
                0,
                GUID_DEVINTERFACE_VOLUME
            };
    
            m_hDevNotify = RegisterDeviceNotification(m_statusHandle,
                 &NotificationFilter, DEVICE_NOTIFY_SERVICE_HANDLE);
    

    note than need use GUID_DEVINTERFACE_VOLUME if you want volume arrival/removal notification but not GUID_DEVCLASS_VOLUME (you use it as { 0x71a27cdd, 0x812a, 0x11d0, 0xbe, 0xc7, 0x08, 0x00, 0x2b, 0xe2, 0x09, 0x2f };). with GUID_DEVCLASS_VOLUME you never got notifications, because this is not interface guid. you got notifications only because use set DEVICE_NOTIFY_ALL_INTERFACE_CLASSES flag - Notifies the recipient of device interface events for all device interface classes. (The dbcc_classguid member is ignored.)

    then in handler - you must got dbcc_devicetype == DBT_DEVTYP_DEVICEINTERFACE type of notification (not DBT_DEVTYP_VOLUME) also will be dbcc_classguid == GUID_DEVINTERFACE_VOLUME if you register exactly for GUID_DEVINTERFACE_VOLUME only. so you can cast lpEventData to PDEV_BROADCAST_DEVICEINTERFACE and use dbcc_name member - this is win32 symbolic link to volume name (can be used in call CreateFileW)