【问题标题】:Drive Letter to Device Instance ID驱动器号到设备实例 ID
【发布时间】:2009-07-27 09:18:41
【问题描述】:

如何从驱动器号获取设备实例 ID?

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

我已经搜索了各种 Setup API 项;但我没有找到任何可以让我从驱动器号到设备实例 ID 的东西。

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

提前谢谢...

【问题讨论】:

    标签: windows device hardware-interface device-instance-id


    【解决方案1】:

    你不能直接这样做。

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

    【讨论】:

      【解决方案2】:

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

      我也有同样的需求,这是我的主要做法:

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

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

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

      -如果 wParam == DBT_DEVICEARRIVAL,当您收到它时,请使用 lParam 检查它是 DBT_DEVTYPE_VOLUME(我在此处获取驱动器的字母和类型)还是 DBT_DEVTYPE_DEVICEINTERFACE(您可以使用您精心制作的 lParam从输入结构中获取 InstanceId)。

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

      如果您阅读本文并需要更多信息,如果有很多人需要,我会回复或提供完整的文档答案。

      希望对你们中的一些人有所帮助。

      【讨论】:

        【解决方案3】:

        我知道那是几年后的事了,但我不得不这样做,搜索把我带到了这里,@DanDan 的回答奏效了。为了为未来的人们节省大量工作,我想我会回馈一些并更明确地介绍该技术。您仍然需要编写一些代码,但我发现困难的部分如下代码:

        正如 DanDan 所提到的,这个想法是使用CreateFile 和DeviceIoControl 来获取与文件路径关联的磁盘的 Windows STORAGE_DEVICE_NUMBER,然后使用 Setup 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://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;
        }
        

        我希望这能让别人头疼

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-10-02
          • 2017-07-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多