Буква диска в идентификатор экземпляра устройства

Как мне перейти от буквы диска к идентификатору экземпляра устройства?

Мой процесс начинается с сообщения о прибытии устройства. Мне удалось получить букву диска из сообщения о прибытии и открыть лоток для DVD.

Я искал различные пункты настройки API; но я не нашел ничего, что могло бы привести меня от буквы диска к идентификатору экземпляра устройства.

Решение на C# или VB.NET было бы идеальным, но я готов выяснить это на любом другом языке, пока я вижу вызовы API.

Заранее спасибо...

2 ответа

Вы не можете сделать это напрямую.

Ссылка для использования STORAGE_DEVICE_NUMBER, Вы можете использовать DeviceIoControl с IOCTL_STORAGE_GET_DEVICE_NUMBER на вашем устройстве имя, чтобы заполнить эту структуру. Поместите это значение в одну сторону.
Затем вам нужно получить информацию об устройстве в вашей системе, используя SetupDiGetClassDevs установив GUIDS в качестве оценочного, указав диски, в которых вы заинтересованы. Затем перечислите устройства, использующие SetupDiEnumDeviceInfo, Затем перечислите интерфейсы, используя SetupDiEnumDeviceInterfaces и, наконец, получить информацию, используя SetupDiGetDeviceInterfaceDetail, В этой возвращенной структуре вы можете получить DevicePath, который вы можете использовать для получения STORAGE_DEVICE_NUMBER как указано выше. Сопоставьте это с STORAGE_DEVICE_NUMBER из вашей буквы диска, и теперь вы связали букву драйвера с вашей структурой. Уф! Внутри этой структуры находится DevInst.

Я знаю, что это годы спустя, но мне пришлось это сделать, и поиск привел меня сюда, и ответ @DanDan сработал. Чтобы сэкономить будущим людям много работы, я подумал, что верну немного и представлю технику более подробно. Вам все равно придется написать немного кода, но часть, которую я нашел трудной, находится ниже в виде кода:

Как упоминал DanDan, идея состоит в том, чтобы использовать CreateFile а также DeviceIoControl получить винду STORAGE_DEVICE_NUMBER для диска, связанного с путем к файлу, а затем используйте API установки для перечисления дисковых устройств, пока мы не найдем одно, чей экземпляр устройства равен SDN.

Во-первых, вот краткое изложение того, как получить STORAGE_DEVICE_NUMBER с пути (например, c:\\users\\bob);

  1. Удалите путь к корню (например, до C:) и добавьте к нему \\\\.\\ так что у тебя есть \\\\.\\C:
  2. Откройте этот путь, используя CreateFileW с, чтобы получить метаданные
  3. Использовать DeviceIoControl с участием IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS получить экстенты
  4. Получить DiskNumber член из первой степени вернулся.
  5. Закройте файл
  6. Открыть \\\\.\\PhysicalDrive<n> где <n> это то, что DiskNumber из первого экстента
  7. Использовать DeviceIoControl с кодом IOCTL_STORAGE_GET_DEVICE_NUMBER чтобы заставить его заполнить STORAGE_DEVICE_NUMBER структура как вывод
  8. Использовать SetupDiGetClassDevs с аргументами &GUID_DEVCLASS_DISKDRIVE а также DICGF_PRESENT получить все диски в системе
  9. В цикле используйте SetupDiEnumDeviceInfo чтобы получить SP_DEVINFO_DATA повторно (в списке устройств, возвращенном на шаге #8 выше) и вызовите функцию ниже, чтобы определить, какое из них, если таковое имеется, соответствует STORAGE_DEVICE_NUMBER для уступки пути.

(Это отредактировано, чтобы удалить мои настраиваемые служебные классы прямо на веб-странице SO, поэтому я мог ввести ошибки / опечатки)

bool DoesDeviceInstanceEqualStorageDeviceNumber(
    const std::string&      devInstance, 
    STORAGE_DEVICE_NUMBER   sdn)
{   
    // Open up this device instance, specifying that we want the *interfaces*.
    // The interfaces are key key because examining them will let us get a 
    // string we can use the Win32 CreateFile function.  

    const auto hDevInfo = SetupDiGetClassDevsA(
        nullptr,
        devInstance.c_str(), 
        nullptr, 
        DIGCF_DEVICEINTERFACE | DIGCF_ALLCLASSES);

    if (hDevInfo == INVALID_HANDLE_VALUE)
        throws std::runtime_error("Unable to get disk devices");


    DWORD dwSize = 0;
    SP_DEVINFO_DATA did;
    WCHAR buffer[4096];

    did.cbSize = sizeof (did);
    bool foundValidMatch = false;
    int deviceNumber = 0;

    // Iterate through all such devices, looking for one that has a storage device number that matches the given one.

    while ( !foundValidMatch &&  SetupDiEnumDeviceInfo(hDevInfo, deviceNumber, &did))
    {
        deviceNumber++;

        DEVPROPTYPE devPropType;

        // We'll only bother comparing this one if it is fixed.  Determine that.

        const auto getPropResult = SetupDiGetDevicePropertyW (
            hDevInfo, 
            &did, 
            &DEVPKEY_Device_RemovalPolicy,  // Ask for the "removal policy"
            &devPropType, 
            (BYTE*)buffer, 
            sizeof(buffer), 
            &dwSize, 
            0);

        if (!getPropResult)
        {
            std::cerr << "Unable to to get removal policy for disk device: " << ::GetLastError() << std::endl;
            continue;
        }

        /*  This bit *would* skip removable disks, you wanted...
        else if (buffer[0] != 1)
        {
  
            std::cerr << "Skipping removable disk device " << devInstance << std::endl;
            continue;
        }
        */

        // OK this is a fixed disk so it might be the one we'll compare against
        // 1. Get the very first disk interface from this particular disk device
        // 2. Open a file on it
        // 3. Query the resulting file for its device number.
        // 4. Compare the device number to the one we determined above
        // 5. If it matches ours, then we succeed.  If not, continue

        SP_DEVICE_INTERFACE_DATA devIntData;
        devIntData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);

        // Get the disk interfaces
        const auto result = SetupDiEnumDeviceInterfaces(
            hDevInfo,
            &did, //&did,
            &GUID_DEVINTERFACE_DISK, // Get Disk Device Interface (from winioctl.h)
            0,                       // We only need the very FIRST one.  I think...
            &devIntData);

        if (!result)
            continue;

        DWORD dwRequiredSize = 0;

        // Want to get the detail but don't yet know how much space we'll need
        // Do a dummy call to find out

        SetupDiGetDeviceInterfaceDetail(
            hDevInfo, 
            &devIntData, 
            nullptr, 
            0, 
            &dwRequiredSize, 
            nullptr);

        if (ERROR_INSUFFICIENT_BUFFER != ::GetLastError())
        {
            std::cerr << "Unable to get device interface Detail: " << ::GetLastError() << std::endl;;
        }
        else
        {

            // Get the detail data so we can get the device path and open a file.

            std::vector<TCHAR> buf(dwRequiredSize);
            auto pDidd = reinterpret_cast<PSP_DEVICE_INTERFACE_DETAIL_DATA>(buf.data());

            // WARNING: HARD CODED HACK
            // ------------------------
            // https://stackru.com/questions/10405193/vb-net-hid-setupdigetdeviceinterfacedetail-getlasterror-shows-1784-error-inv
            //
            // Don't ask.  Just do what they tell you. 
            // -----------------------------------------------------------------
#ifdef BUILD_64
            pDidd->cbSize = 8;
#else
            pDidd->cbSize = 6;
#endif
            // -----------------------------------------------------------------

            if (!SetupDiGetDeviceInterfaceDetail(
                hDevInfo, 
                &devIntData, 
                pDidd, 
                dwRequiredSize, 
                &dwRequiredSize, 
                nullptr))
            {
                std::cerr << "Cannot get interface detail: " << ::GetLastError());
            }
            else
            {
                // FINALLY:  We now have a DevicePath that we can use to open up
                // in a Win32 CreateFile() call.   That will let us get the
                // STORAGE_DEVICE_NUMBER and compare it to the one we were given.

                const auto hFile = ::CreateFileW(pDidd->DevicePath, 0, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, NULL);
                if (INVALID_HANDLE_VALUE != hFile)
                {
                    std::cerr << "Unable to open logical volume: " + devicePath << std::endl;
                    continue;
                }
 
                STORAGE_DEVICE_NUMBER sdnTest;
                ZeroMemory(&sdnTest, sizeof(STORAGE_DEVICE_NUMBER));


                if (0 == DeviceIoControl(
                     hDevInfo
                     IOCTL_STORAGE_GET_DEVICE_NUMBER,
                     nullptr,            // output only so not needed
                     0,                  // output only so not needed
                     &sdnTest,
                     sizeof(STORAGE_DEVICE_NUMBER),
                     nullptr, 
                     nullptr))
                {
                    std::cerr << "Unable to determine storage device number: " << ::GetLastError() << std::endl;);
                }
                else
                {
                    // All this for a one-line test...

                    foundValidMatch = sdnTest.DeviceNumber == sdn.DeviceNumber; 
                }
            }
        }
    }
    SetupDiDestroyDeviceInfoList(hDevInfo);
    return foundValidMatch;
}

Надеюсь, это избавит кого-то от головной боли

Я знаю, что уже поздно для тебя, но не для всех ^^

У меня была такая же потребность, и это основная линия того, как я это сделал:

-Вы должны иметь окно для получения устройства прибытия и удаления (как вы сказали)

-Тогда вы создаете DeviceNotificationFilter, инициированный для dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE

-Тогда в цикле сообщений вашего окна вы ищете VM_DEVICECHANGE

-Если вы получите его, если wParam == DBT_DEVICEARRIVAL, используйте lParam, чтобы проверить, является ли это DBT_DEVTYPE_VOLUME (я получал здесь букву и тип диска) или DBT_DEVTYPE_DEVICEINTERFACE (там вы можете использовать свой lcastek для получения из структуры ввода).

Когда вы подключаете диск, сначала вы получаете DEVINTERFACE, а затем другой. Я даю только основную строку, потому что я сделал это давным-давно, и у меня нет кода здесь, а также я нашел много фрагментов кода в сети (давно, так что теперь должно быть больше ^^^) Может быть, MSDN дать полный пример кода, чтобы сделать это сейчас.

Если вы прочитаете это и вам потребуется дополнительная информация, я отвечу или сделаю полный документальный ответ, если многим это нужно.

Надеюсь, это поможет некоторым из вас.

Другие вопросы по тегам