Не удается определить диск моего USB-устройства - PullRequest
0 голосов
/ 20 апреля 2020

Я пишу программу для обнаружения, когда вставлен USB-накопитель. При вставке USB-накопителя он определяется как DBT_DEVTYP_DEVICEINTERFACE, но не как DBT_DEVTYP_VOLUME. Поэтому я не могу получить букву диска тома (A, B, C, D, ...). Как я могу решить эту проблему, т.е. сделать его обнаруживаемым как DBT_DEVTYP_VOLUME или получить букву диска другим способом.

    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;
        for (int i = 0; i < sizeof(GuidDevInterfaceList); i++) {
            NotificationFilter.dbcc_classguid = GuidDevInterfaceList[i];

            HDEVNOTIFY dev_notify = RegisterDeviceNotification(hwnd, &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE);
            if (dev_notify == NULL) {     // Handle the error by returning correct error in LRESULT format and remove throw...   
                throw std::runtime_error("Could not register for device Notifications!");
            }
        }

    }
    break;

        case WM_DEVICECHANGE:
        {

            PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)lparam;   

                                        //DBT_DEVTYP_VOLUME
            if (lpdb->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
            {

                switch (wparam)
                {

                case DBT_DEVICEARRIVAL: 
                {                   
                    cout<<"Device Arrived"<<endl;

                }
    }}}}}

Он обнаруживает, что устройство вставлено

ВЫХОД:

Device Arrived
Failed

1 Ответ

1 голос
/ 20 апреля 2020

Убедитесь, что вы используете GUID_DEVINTERFACE_VOLUME для регистрации уведомления устройства.

Обходной путь (если том (ы) вашего USB принадлежит новому диску) должен использовать GetLogicalDrives проверка измененной маски устройства после прибытия устройства:

LRESULT message_handler(HWND__* hwnd, UINT uint, WPARAM wparam, LPARAM lparam)
{
    static DWORD current_unit_mask = 0;
    switch (uint)
    {
    //...
    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;
        for (int i = 0; i < sizeof(GuidDevInterfaceList); i++) {
            NotificationFilter.dbcc_classguid = GuidDevInterfaceList[i];

            HDEVNOTIFY dev_notify = RegisterDeviceNotification(hwnd, &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE);
            if (dev_notify == NULL) {     // Handle the error by returning correct error in LRESULT format and remove throw...   
                throw std::runtime_error("Could not register for device Notifications!");
            }
        }
        current_unit_mask = GetLogicalDrives(); //Get the initial value
    }
    break;

    case WM_DEVICECHANGE:
    {

        PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)lparam;

        //DBT_DEVTYP_VOLUME
        if (lpdb->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
        {

            switch (wparam)
            {

            case DBT_DEVICEARRIVAL:
            {
                cout << "Device Arrived" << endl;
                DWORD tmpmask = GetLogicalDrives();
                DWORD changed_mask = tmpmask ^ current_unit_mask; //changed_mask stores the uintmask of the changed device
                current_unit_mask = tmpmask; //update current_unit_mask

            }break;
            }
        }
    }
    }
}

Спасибо, что @RbMm указал, что накопитель может иметь несколько томов, и том можно вставить без добавления в новый диск. Таким образом, вышеприведенная логика c может отслеживать изменения объемов:

#include <windows.h> 
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <iterator>
using namespace std;
vector<wstring> GetVolumePaths(vector<wstring> volumes)
{
    DWORD  ReturnLength = 0;
    WCHAR Names[MAX_PATH] = { 0 };
    PWCHAR NameIdx = NULL;
    BOOL   Success = FALSE;
    vector<wstring> VolumePaths;
    for (int i = 0; i < volumes.size(); i++)
    {
        for (;;)
        {
            Success = GetVolumePathNamesForVolumeNameW(volumes[i].c_str(), Names, MAX_PATH, &ReturnLength);

            if (Success)
            {
                break;
            }

            if (GetLastError() != ERROR_MORE_DATA)
            {
                break;
            }

        }
        if (Success)
        {
            for (NameIdx = Names;
                NameIdx[0] != L'\0';
                NameIdx += wcslen(NameIdx) + 1)
            {
                wprintf(L"  %s", NameIdx);
                VolumePaths.push_back(NameIdx);
            }
            wprintf(L"\n");
        }

    }
    return VolumePaths;
}
vector<wstring> GetDiff(vector<wstring> v1, vector<wstring> v2)
{
    vector<wstring> diff;
    std::sort(v1.begin(), v1.end());
    std::sort(v2.begin(), v2.end());
    std::set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(),
        std::inserter(diff, diff.begin()));
    return diff;
}

vector<wstring> FindVolume()
{
    DWORD  CharCount = 0;

    DWORD  Error = ERROR_SUCCESS;
    HANDLE FindHandle = INVALID_HANDLE_VALUE;
    size_t Index = 0;
    BOOL   Success = FALSE;
    WCHAR  VolumeName[MAX_PATH] = L"";
    vector<wstring> volumes;

    FindHandle = FindFirstVolumeW(VolumeName, ARRAYSIZE(VolumeName));
    if (FindHandle == INVALID_HANDLE_VALUE)
    {
        Error = GetLastError();
        wprintf(L"FindFirstVolumeW failed with error code %d\n", Error);
        return volumes;
    }
    volumes.push_back(VolumeName);
    for (;;)
    {
        //
        //  Skip the \\?\ prefix and remove the trailing backslash.
        Index = wcslen(VolumeName) - 1;

        if (VolumeName[0] != L'\\' ||
            VolumeName[1] != L'\\' ||
            VolumeName[2] != L'?' ||
            VolumeName[3] != L'\\' ||
            VolumeName[Index] != L'\\')
        {
            Error = ERROR_BAD_PATHNAME;
            wprintf(L"FindFirstVolumeW/FindNextVolumeW returned a bad path: %s\n", VolumeName);
            break;
        }

        Success = FindNextVolumeW(FindHandle, VolumeName, ARRAYSIZE(VolumeName));
        if (!Success)
        {
            Error = GetLastError();
            if (Error != ERROR_NO_MORE_FILES)
            {
                wprintf(L"FindNextVolumeW failed with error code %d\n", Error);
                break;
            }
            Error = ERROR_SUCCESS;
            break;
        }
        volumes.push_back(VolumeName);
    }

    FindVolumeClose(FindHandle);
    FindHandle = INVALID_HANDLE_VALUE;
    return volumes;
}


LRESULT message_handler(HWND__* hwnd, UINT uint, WPARAM wparam, LPARAM lparam)
{
    static vector<wstring> current_volumes;
    switch (uint)
    {
    //...
    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;
        for (int i = 0; i < sizeof(GuidDevInterfaceList); i++) {
            NotificationFilter.dbcc_classguid = GuidDevInterfaceList[i];

            HDEVNOTIFY dev_notify = RegisterDeviceNotification(hwnd, &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE);
            if (dev_notify == NULL) {     // Handle the error by returning correct error in LRESULT format and remove throw...   
                throw std::runtime_error("Could not register for device Notifications!");
            }
        }
        current_unit_mask = FindVolume();
    }
    break;

    case WM_DEVICECHANGE:
    {

        PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)lparam;

        //DBT_DEVTYP_VOLUME
        if (lpdb->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
        {

            switch (wparam)
            {

            case DBT_DEVICEARRIVAL:
            {
                cout << "Device Arrived" << endl;
                vector<wstring> tmp = FindVolume();
                vector<wstring> change_volumes = GetDiff(tmp, current_volumes);
                vector<wstring> VolumePaths = GetVolumePaths(change_volumes);
                current_volumes = tmp;
                for(int i = 0; i < VolumePaths.size(); i++)
                {
                    wprintf(L"   %s\n", VolumePaths[i]);
                }
            }break;
            }
        }
    }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...