c++ - 在插入或移除时获取 USB 的 dos_name

标签 c++ winapi

我设计了一个程序来检测何时连接或移除 USB 设备。我想知道dos path连接的设备或这样的 Guid \\?\Volume{17ee3574-7082-4881-aeae-07893db4e957}\而是 dbcc_name给我\\?\STORAGE#Volume#_??_USBSTOR#Disk&Ven_JetFlash&Prod_Transcend_8GB&Rev_1100#546IYBDAPBE1075Q&0#{53f56307-b6bf-11d0-94f2-00a0c91efb8b}#{53f5630d-b6bf-11d0-94f2-00a0c91efb8b}无论如何要获得连接的逻辑驱动器的guid或其dos名称。我的代码是:

#define CLS_NAME L"USB_LISTENER_CLASS"
#define HID_CLASSGUID {0x4d1e55b2, 0xf16f, 0x11cf,{ 0x88, 0xcb, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30}}
LRESULT message_handler(HWND__* hwnd, UINT uint, WPARAM wparam, LPARAM lparam)
{
    
    switch (uint)
    {
    case WM_NCCREATE: // before window creation
        return true;
        break;

    case WM_CREATE: // the actual creation of the window
    {
        // you can get your creation params here..like GUID..
        LPCREATESTRUCT params = (LPCREATESTRUCT)lparam;
        GUID InterfaceClassGuid = *((GUID*)params->lpCreateParams);
        DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;

        ZeroMemory(&NotificationFilter, sizeof(NotificationFilter));
        NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
        NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
        NotificationFilter.dbcc_classguid = GUID_DEVINTERFACE_VOLUME;

        HDEVNOTIFY dev_notify = RegisterDeviceNotification(hwnd, &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE);
        if (dev_notify == NULL)
        {   
            throw std::runtime_error("Could not register for device Notifications!");
        }

    }
    break;

    case WM_DEVICECHANGE:
    {

        PDEV_BROADCAST_HDR(lpdb) = (PDEV_BROADCAST_HDR)lparam;
        PDEV_BROADCAST_DEVICEINTERFACE_W lpdbv = (PDEV_BROADCAST_DEVICEINTERFACE_W)lpdb;
        switch (wparam)
        {

            case DBT_DEVICEARRIVAL:     //A device or piece of media has been inserted and is now available.

                std::cout << "Device Arrived" << std::endl;
                std::cout << "GUID od inserted device: " << lpdbv->dbcc_name;
                break;

            case DBT_DEVICEREMOVECOMPLETE:
                std::cout << "Device Removed" << std::endl;
                break;
        }
        
    }

    }
    return 0L;
}
void UsbListener::RegisterListener()
{
    HWND hWnd = NULL;
    WNDCLASSEXW wx;
    ZeroMemory(&wx, sizeof(wx));
    wx.cbSize = sizeof(WNDCLASSEX);
    wx.lpfnWndProc = reinterpret_cast<WNDPROC>(message_handler);
    wx.hInstance = reinterpret_cast<HINSTANCE>(GetModuleHandle(0));
    wx.style = CS_HREDRAW | CS_VREDRAW;
    wx.hInstance = GetModuleHandle(0);
    wx.hbrBackground = (HBRUSH)(COLOR_WINDOW);
    wx.lpszClassName = CLS_NAME;
    GUID guid = HID_CLASSGUID;
    if (RegisterClassExW(&wx))
    {
        hWnd = CreateWindowW(
            CLS_NAME, L"DeviceNotificationWindow", WS_ICONIC, 0, 0, CW_USEDEFAULT, 0, HWND_MESSAGE, NULL, GetModuleHandle(0), (void*)&guid
        );
    }
    if (hWnd == NULL)
    {
        throw std::runtime_error("Could not create message window!");
    }
    std::cout <<std::endl<< "Listening..." << std::endl;
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }   
}
我想知道插入或删除的确切驱动器的 Dos 名称,以便 UI 可以显示。我是winapi的新手,所以请耐心等待代码,

最佳答案

一开始你需要打开Mount Manager并将它的句柄保存在与您的窗口关联的类中,因为不会多次打开/关闭它,仅位一次

#include <mountmgr.h>

HANDLE hMountMgr = CreateFileW(MOUNTMGR_DOS_DEVICE_NAME, 0, 0, 0, OPEN_EXISTING, 0, 0);
对于类似名称的查询(如果存在!),您需要先获取 device name通过 IOCTL_MOUNTDEV_QUERY_DEVICE_NAME 哪个需要发送到设备,你有哪个接口(interface)名称。所以你需要先打开它。
那么你可以发送IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH到 Mount Manager 并得到你想要的
volatile UCHAR guz;

ULONG GetDosVolumePath(HANDLE hMountMgr, PCWSTR InterfaceLink, PWSTR* ppszDosPath)
{
    *ppszDosPath = 0;

    HANDLE hFile = CreateFileW(InterfaceLink, 0, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);

    if (hFile == INVALID_HANDLE_VALUE) return GetLastError();

    union {
        PVOID buf;
        PMOUNTDEV_NAME pmdn;
    };

    ULONG dwError;

    PVOID stack = alloca(guz);
    ULONG cb = 0, rcb, InputBufferLength = sizeof(MOUNTDEV_NAME) + 0x40;

    do 
    {
        if (cb < InputBufferLength)
        {
            cb = RtlPointerToOffset(buf = alloca(InputBufferLength - cb), stack);
        }

        dwError = BOOL_TO_ERROR(DeviceIoControl(hFile, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, 0, 0, pmdn, cb, &rcb, 0));

        InputBufferLength = FIELD_OFFSET(MOUNTDEV_NAME, Name) + pmdn->NameLength;

    } while ( dwError == ERROR_MORE_DATA);

    CloseHandle(hFile);

    if (dwError == NOERROR)
    {
        union {
            PVOID pv;
            PMOUNTMGR_VOLUME_PATHS pmvp;
        };

        cb = 0, rcb = sizeof(MOUNTMGR_VOLUME_PATHS) + 8;

        do 
        {
            if (cb < rcb)
            {
                cb = RtlPointerToOffset(pv = alloca(rcb - cb), pmdn);
            }

            dwError = BOOL_TO_ERROR(DeviceIoControl(hMountMgr, 
                IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH, 
                pmdn, InputBufferLength, pmvp, cb, &rcb, 0));

            if (dwError == NOERROR)
            {
                *ppszDosPath = _wcsdup(pmvp->MultiSz);
            }

            rcb = FIELD_OFFSET(MOUNTMGR_VOLUME_PATHS, MultiSz) + pmvp->MultiSzLength;

        } while (dwError == ERROR_MORE_DATA);
    }

    return dwError;
}

关于c++ - 在插入或移除时获取 USB 的 dos_name,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62853331/

相关文章:

c++ - 如何修复内存不足错误(openCV)

c# - 在 Windows 中如何从 USB HID 设备获取原始描述符数据?

c++ - C++ 会优化空/非虚拟/无效方法调用吗?

windows - 触摸屏隐藏光标

c++ - 资源中的 CRichEditCtrl 加载 1.0 而不是 2.0

c++ - 了解 std::move() 的代码

c++ - 在完美转发函数中公开参数类型,避免代码重复

c - 获取父进程名称 (Windows)

c++ - 如何使用 C++ win32 API 将 Variant Safe Array 转换为 Char?

c - PostQuitMessage() 不会关闭我的应用程序?