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

为什么有些设备不使用SetupDiGetDeviceInterfaceDetails()枚举?

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

    我正在维护一个应用程序,该应用程序使用SetupDiGetDeviceInterfaceDetails()来查找计算机上已安装串行端口的信息。在测试过程中,我注意到有些设备,比如我的LucentWinModem,没有出现在该枚举中。事实证明,我公司制造的一组实现串行端口接口的设备也存在类似的问题。我的假设是,设备的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页面的标志(最后一个参数)指定了什么:

    DIGCF_ALLCLASSES 返回所有设备设置类或所有已安装设备的列表

    DIGCF_device接口 接口类。此标志必须 如果满足以下条件,请在Flags参数中设置

    DIGCF_DEFAULT 仅返回与系统默认值关联的设备 设备接口(如果已设置),用于 指定的设备接口 班级。

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

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

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


    更新:谢谢你的示例代码。

    我现在的问题是,如果你想知道调制解调器的友好名称,为什么不使用相同的调用,而是指定调制解调器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

    据我所知,设备接口被用来获取可用于写入的设备路径。

    为了测试你的代码,我做了一件事,就是在磁盘设备接口上重试。我做了一些更改,让它在我的系统上运行,但还没有完全完成。我认为一个问题(可能更多)是,我需要在SetupDiGetDeviceInterfaceDetails调用之间调整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

        3
  •  0
  •   Windows programmer    16 年前

        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