驱动器号到设备实例ID

时间:2009-07-27 09:18:41

标签: windows device hardware-interface

如何从驱动器号转到设备实例ID?

我的流程从设备到达消息开始。我已经成功地从到达消息和打开DVD托盘中获取驱动器号。

我搜索了各种Setup API项目;但是我没有找到任何能让我从驱动器号转到设备实例ID的内容。

C#或VB.NET中的解决方案是理想的,但只要我能看到API调用,我就愿意从任何其他语言中找到它。

提前致谢...

3 个答案:

答案 0 :(得分:4)

你不能直接这样做。

链接是使用STORAGE_DEVICE_NUMBER。您可以在设备名称上使用带有IOCTL_STORAGE_GET_DEVICE_NUMBER的DeviceIoControl来填充此结构。把这个值放在一边 然后,您需要使用SetupDiGetClassDevs将GUID设置为适当的方式在您的系统上获取设备信息,指示您感兴趣的驱动器。然后使用SetupDiEnumDeviceInfo枚举设备。然后使用SetupDiEnumDeviceInterfaces枚举接口,最后使用SetupDiGetDeviceInterfaceDetail获取信息。在返回的此结构中,您可以获得可用于获取STORAGE_DEVICE_NUMBER的DevicePath,如上所述。将其与您的驱动器号中的STORAGE_DEVICE_NUMBER相匹配,现在您已将驱动器号与您的结构相关联。唷!在这个结构里面是一个DevInst。

答案 1 :(得分:1)

我知道现在已经很晚了,但不是每个人都知道^^

我有同样的需求,这是我如何做到的主线:

- 你需要一个窗口来接收和移除设备(如你所说)

- 然后创建一个启动到dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE的DeviceNotificationFilter

- 然后在窗口的消息循环中查找VM_DEVICECHANGE

- 如果wParam == DBT_DEVICEARRIVAL你收到它,请使用lParam来检查它是否是DBT_DEVTYPE_VOLUME(我在这里得到了字母和驱动器的类型)或DBT_DEVTYPE_DEVICEINTERFACE(你可以使用你的wellPated lParam来从输入结构中获取InstanceId。

连接驱动器时,首先接收DEVINTERFACE,然后接收另一个。 我只给了主线因为我很久以前就这么做了,我没有这里的代码,而且我在网上找到了很多代码片段(很久以前所以现在应该有更多的^^^)也许msdn现在提供一个完整的代码示例。

如果您阅读此内容并需要更多信息,如果有需要,我会回复或提供完整的文件回答。

希望它会帮助你们中的一些人。

答案 2 :(得分:0)

我知道已经过了几年,但是我不得不这样做,搜索将我带到了这里,@ DanDan的答案起作用了。为了节省将来的人们很多工作,我想我会回馈一点,并更明确地介绍这项技术。您仍然需要编写一些代码,但是我发现困难的部分如下所示:

如DanDan所述,其想法是使用CreateFileDeviceIoControl来获取与文件路径关联的磁盘的Windows STORAGE_DEVICE_NUMBER,然后使用Setup API枚举磁盘直到找到一个其设备实例等于SDN的设备。

首先,这是如何从路径中获取STORAGE_DEVICE_NUMBER的摘要(例如c:\\users\\bob);

  1. 将路径扩展到根(例如,降到C:)并在其前面加上\\\\.\\,这样您就拥有\\\\.\\C:
  2. 使用CreateFileW与该路径打开以获取元数据
  3. DeviceIoControlIOCTL_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_DISKDRIVEDICGF_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://stackoverflow.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;
}

我希望这可以使人免于头痛