代码之家  ›  专栏  ›  技术社区  ›  Jon Trauntvein

为什么有些设备不能用SETUPDIGETDeviceInterfaceDetail()枚举?

  •  1
  • Jon Trauntvein  · 技术社区  · 16 年前

    我正在维护一个应用程序,该应用程序使用SETUPDIGETDeviceInterfaceDetail()查找有关计算机上已安装串行端口的信息。在测试时,我注意到有些设备,如我的Lucent WinModem,没有出现在枚举中。事实证明,我和我公司生产的一组实现串行端口接口的设备有类似的问题。我的假设是设备的INF文件中缺少某些内容。有人知道什么样的条件会导致这种遗漏吗?

    编辑:这里是我用来枚举串行端口的代码示例。我尝试过各种旗帜组合,但在行为上没有看到任何显著的区别。

    DEFINE_GUID(GUID_CLASS_COMPORT, 0x4d36e978, 0xe325, 0x11ce, 0xbf, 0xc1, \
                0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18);
    
    
    GUID *serial_port_guid = const_cast<GUID *>(&GUID_CLASS_COMPORT);
    HDEVINFO device_info = INVALID_HANDLE_VALUE;
    SP_DEVICE_INTERFACE_DETAIL_DATA *detail_data = 0;
    
    device_info = SetupDiGetClassDevs(
       serial_port_guid, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
    if(device_info != INVALID_HANDLE_VALUE)
    {
       uint4 const detail_data_size = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) + 256;
       detail_data = reinterpret_cast<SP_DEVICE_INTERFACE_DETAIL_DATA *>(new char[detail_data_size]);
       SP_DEVICE_INTERFACE_DATA ifc_data;
       bool more_interfaces = true;
       int rcd;
       memset(&ifc_data, 0, sizeof(ifc_data)); 
       memset(detail_data, 0, detail_data_size);
       ifc_data.cbSize = sizeof(ifc_data);
       detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
       for(uint4 index = 0; more_interfaces; ++index)
       {
          rcd = SetupDiEnumDeviceInterfaces(device_info, 0, serial_port_guid, index, &ifc_data);
          if(rcd)
          {
             // we need to get the details of this device
             SP_DEVINFO_DATA device_data = { sizeof(SP_DEVINFO_DATA) };
             rcd = SetupDiGetDeviceInterfaceDetail(
                device_info, &ifc_data, detail_data, detail_data_size, 0, &device_data);
             if(rcd)
             {
                StrAsc device_path(detail_data->DevicePath);
                byte friendly_name[256];
    
                rcd = SetupDiGetDeviceRegistryProperty(
                   device_info, &device_data, SPDRP_FRIENDLYNAME, 0, friendly_name, sizeof(friendly_name), 0);
                if(rcd)
                {
                   std::for_each(
                      port_names.begin(),
                      port_names.end(),
                      update_friendly_name(
                         reinterpret_cast<char const *>(friendly_name)));
                }
             }
             else
                more_interfaces = false;
          }
       }
    }
    
    4 回复  |  直到 16 年前
        1
  •  4
  •   Rob Haupt    16 年前

    这更像是一个关于这个问题的问题。调用函数时,传递的第一个参数应该是deviceinfoset,这可能是从 SetupDiGetClassDevs 功能。调用SETUPDIGETCLASSDEVS函数时,为函数上引用Microsoft页面的标志(最后一个参数)指定了什么:

    所有课程 返回所有设备安装类或所有设备的已安装设备列表 设备接口类。

    数字设备接口 返回支持指定设备的设备接口的设备 接口类。此标志必须是 在Flags参数中设置 枚举器参数指定 设备实例ID。

    缺省违约 仅返回与系统默认值关联的设备 设备接口(如果已设置),用于 指定的设备接口 类。

    DigCFION 仅返回系统中当前存在的设备。

    DigCFX轮廓 仅返回属于当前硬件配置文件的设备。

    根据您的选择,设备列表会发生更改。例如,当前标志将只显示活动插入的设备。


    更新:感谢您提供示例代码。

    我现在的问题是,如果您想知道调制解调器的友好名称,为什么不使用相同的呼叫,但指定调制解调器的GUID而不是COM端口?我的调制解调器guid是4d36e96d-e325-11ce-bfc1-08002be10318

    在注册表中,我可以看到一个名为“attachedto”的值,它指定了一个COM端口。我必须研究API中的哪些属性。注册表项位于

    hklm\system\currentcontrolset\control\class 4d36e96d-e325-11ce-bfc1-08002be10318 \


    另一个更新:

    仔细观察示例代码。基于此,如果您尝试获取应返回 SP_DEVICE_INTERFACE_DETAIL_DATA 结构。这并不能提供一种获取设备友好名称的方法。我相信你会想要这个设备实例。

    从我读到的内容来看,设备接口被用来作为获取设备路径的一种方法,该路径可用于写入设备。

    我做了一件事来测试你的代码,那就是在磁盘设备接口上再试一次。我做了一些修改让它在我的系统上工作,但它还没有完全完成。我认为一个问题(可能更多)是我需要在SETUPDIGETDeviceInterfaceDetail调用之间调整devicePath变量的大小。

    void Test()
    {
    
    GUID *serial_port_guid = const_cast<GUID *>(&GUID_DEVINTERFACE_DISK);
    HDEVINFO device_info = INVALID_HANDLE_VALUE;
    SP_DEVICE_INTERFACE_DETAIL_DATA detail_data;
    
    device_info = SetupDiGetClassDevs(
       serial_port_guid, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
    if(device_info != INVALID_HANDLE_VALUE)
    {
       //uint4 const detail_data_size = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);// + 256;
       //detail_data = reinterpret_cast<SP_DEVICE_INTERFACE_DETAIL_DATA *>(new char[detail_data_size]);
       SP_DEVICE_INTERFACE_DATA ifc_data;
       bool more_interfaces = true;
       int rcd;
       memset(&ifc_data, 0, sizeof(ifc_data)); 
       //memset(detail_data, 0, detail_data_size);
       ifc_data.cbSize = sizeof(ifc_data);
       detail_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
       for(uint4 index = 0; more_interfaces; ++index)
       {
          rcd = SetupDiEnumDeviceInterfaces(device_info, 0, serial_port_guid, index, &ifc_data);
          if(rcd)
          {
             // we need to get the details of this device
             SP_DEVINFO_DATA device_data;
             device_data.cbSize = sizeof(SP_DEVINFO_DATA);
             DWORD intReqSize;
             rcd = SetupDiGetDeviceInterfaceDetail(device_info, &ifc_data, 0, 0, &intReqSize, &device_data);
    
             rcd = SetupDiGetDeviceInterfaceDetail(device_info, &ifc_data, &detail_data,intReqSize,&intReqSize,&device_data);
             if(rcd)
             {
                //StrAsc device_path(detail_data->DevicePath);
                byte friendly_name[256];
    
                rcd = SetupDiGetDeviceRegistryProperty(
                   device_info, &device_data, SPDRP_FRIENDLYNAME, 0, friendly_name, sizeof(friendly_name), reinterpret_cast<DWORD *>(sizeof(friendly_name)));
                if(rcd)
                {
                  cout<<reinterpret_cast<char const *>(friendly_name);
                }
                else
                {   int num = GetLastError();
                }
             }
             else
             {
                    int num = GetLastError();
                }
          }
          else
                more_interfaces = false;
       }    
    }
    SetupDiDestroyDeviceInfoList(device_info);
    }
    

    此外,在INF中,您可能需要添加 AddInterface 用于将驱动程序与正确接口关联的指令。

        2
  •  1
  •   lakshmanaraj    16 年前

    我不确定以下修补程序是否可以解决您在中提到的问题

    http://support.microsoft.com/kb/327868

    还有一个有趣的地方:从Win2000起,guid_class_comport已经过时了。

    http://msdn.microsoft.com/en-us/library/bb663140.aspx

    http://msdn.microsoft.com/en-us/library/bb663174.aspx

    我发现另一个网站有9种不同的枚举方式。祝你好运。

    http://www.naughter.com/enumser.html

        3
  •  0
  •   Windows programmer    16 年前

    您说您的设备存在并且可以访问,但您是直接访问您的设备还是通过名称和编号访问端口Comn:

    我有一个连接到音频驱动程序的WinModem。我没有串行端口,甚至没有模拟端口。

        4
  •  -1
  •   Jon Trauntvein    16 年前

    我决定在这个问题上下赌注,去掉对setupdi()函数的依赖。相反,我编写了代码来遍历hkey_local_machine\system\currentcontrolset\enum中的子项,以查找任何支持串行端口guid的驱动程序。我觉得这就是设备管理器所做的。如果有人感兴趣,可以在下面看到我的代码片段:

    typedef std::string StrAsc;
    typedef std::pair<StrAsc, StrAsc> port_name_type;
    typedef std::list<port_name_type> friendly_names_type;
    void SerialPortBase::list_ports_friendly(friendly_names_type &port_names)
    {
       // we will first get the list of names.  This will ensure that, at the very least, we get
       // the same list of names as we would have otherwise obtained. 
       port_names_type simple_list;
       list_ports(simple_list);
       port_names.clear();
       for(port_names_type::iterator pi = simple_list.begin(); pi != simple_list.end(); ++pi)
          port_names.push_back(friendly_name_type(*pi, *pi));
    
       // we will now need to enumerate the subkeys of the Enum registry key. We will need to
       // consider many levels of the registry key structure in doing this so we will use a list
       // of key handles as a stack.
       HKEY enum_key ;
       char const enum_key_name[] = "SYSTEM\\CurrentControlSet\\Enum";
       StrAsc const com_port_guid("{4d36e978-e325-11ce-bfc1-08002be10318}");
       char const class_guid_name[] = "ClassGUID";
       char const friendly_name_name[] = "FriendlyName";
       char const device_parameters_name[] = "Device Parameters";
       char const port_name_name[] = "PortName";
       long rcd = ::RegOpenKeyEx(
          HKEY_LOCAL_MACHINE, enum_key_name, 0, KEY_READ, &enum_key);
       char value_buff[MAX_PATH];
       StrAsc port_name, friendly_name;
    
       if(!port_names.empty() && rcd == ERROR_SUCCESS)
       {
          std::list<HKEY> key_stack;
          key_stack.push_back(enum_key);
          while(!key_stack.empty())
          {
             // we need to determine whether this key has a "ClassGUID" value
             HKEY current = key_stack.front();
             uint4 value_buff_len = sizeof(value_buff);
             key_stack.pop_front();
             rcd = ::RegQueryValueEx(
                current,
                class_guid_name,
                0,
                0,
                reinterpret_cast<byte *>(value_buff),
                &value_buff_len);
             if(rcd == ERROR_SUCCESS)
             {
                // we will only consider devices that match the com port GUID
                if(com_port_guid == value_buff)
                {
                   // this key appears to identify a com port.  We will need to get the friendly name
                   // and try to get the 'PortName' from the 'Device Parameters' subkey.  Once we
                   // have those things, we can update the friendly name in our original list
                   value_buff_len = sizeof(value_buff);
                   rcd = ::RegQueryValueEx(
                      current,
                      friendly_name_name,
                      0,
                      0,
                      reinterpret_cast<byte *>(value_buff),
                      &value_buff_len);
                   if(rcd == ERROR_SUCCESS)
                   {
                      HKEY device_parameters_key;
                      rcd = ::RegOpenKeyEx(
                         current,
                         device_parameters_name,
                         0,
                         KEY_READ,
                         &device_parameters_key);
                      if(rcd == ERROR_SUCCESS)
                      {
                         friendly_name = value_buff;
                         value_buff_len = sizeof(value_buff);
                         rcd = ::RegQueryValueEx(
                            device_parameters_key,
                            port_name_name,
                            0,
                            0,
                            reinterpret_cast<byte *>(value_buff),
                            &value_buff_len);
                         if(rcd == ERROR_SUCCESS)
                         {
                            friendly_names_type::iterator fi;
                            port_name = value_buff;
                            fi = std::find_if(
                               port_names.begin(), port_names.end(), port_has_name(port_name));
                            if(fi != port_names.end())
                               fi->second = friendly_name;
                         }
                         ::RegCloseKey(device_parameters_key);
                      }
                   }
                }
             }
             else
             {
                // since this key did not have what we expected, we will need to check its
                // children
                uint4 index = 0;
                rcd = ERROR_SUCCESS;
                while(rcd == ERROR_SUCCESS)
                {
                   value_buff_len = sizeof(value_buff);
                   rcd = ::RegEnumKeyEx(
                      current, index, value_buff, &value_buff_len, 0, 0, 0, 0);
                   if(rcd == ERROR_SUCCESS)
                   {
                      HKEY child;
                      rcd = ::RegOpenKeyEx(current, value_buff, 0, KEY_READ, &child);
                      if(rcd == ERROR_SUCCESS)
                         key_stack.push_back(child);
                   }
                   ++index;
                }
             }
             ::RegCloseKey(current);
          }
       }
    } // list_ports_friendly