Here's my solution for this, in case anyone's interested:
The header file:
#include <windows.h>
#include <dbt.h>
#include <QObject>
#include <QAbstractNativeEventFilter>
class DeviceEventFilter: public QObject, public QAbstractNativeEventFilter
{
    Q_OBJECT
public:
    DeviceEventFilter(QObject *parent);
    bool nativeEventFilter(const QByteArray &eventType, void *message, long *result)
    Q_DECL_OVERRIDE;
Q_SIGNALS:
    void notify();
};
And the source file:
#include "eventfilter.h"
DeviceEventFilter::DeviceEventFilter(QObject *parent)
{
    Q_UNUSED(parent)
}
bool DeviceEventFilter::nativeEventFilter(const QByteArray &eventType, void *message, long *result)
{
    Q_UNUSED(eventType) // unneeded as long as we're only running on Windows
    Q_UNUSED(result)
    MSG *msg = (MSG *)(message);
    if ((msg->message == WM_DEVICECHANGE)
            && (msg->wParam == DBT_DEVNODES_CHANGED))
    {
        emit notify();
    }
    return false;
}