Pourquoi certains périphériques énumérer pas SetupDiGetDeviceInterfaceDetail ()?

StackOverflow https://stackoverflow.com/questions/571229

  •  05-09-2019
  •  | 
  •  

Question

Je suis maintenant une application qui utilise SetupDiGetDeviceInterfaceDetail () pour trouver des informations sur les ports série installés sur l'ordinateur. Je l'ai remarqué tout en testant ce qu'il ya des dispositifs, tels que mon Lucent WinModem, qui ne se présentent pas dans cette énumération. Il se trouve que j'ai un problème similaire avec un ensemble de dispositifs fabriqués par mon entreprise qui mettent en œuvre l'interface port série. Mon hypothèse est qu'il ya quelque chose qui manque dans le fichier INF pour le périphérique. Est-ce que quelqu'un sait quel genre de conditions peut entraîner ce genre d'omission?

Edit: Voici un exemple du code que je me sers d'énumérer les ports série. J'ai essayé différentes combinaisons de drapeaux mais n'ont pas vu de différence significative dans le comportement.

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;
      }
   }
}
Était-ce utile?

La solution 4

J'ai décidé de punt sur cette question et à en finir avec la dépendance des fonctions SetupDi (). Au lieu de cela, je l'ai écrit du code qui traverse les sous-clés dans HKEY_LOCAL_MACHINE \ System \ CurrentControlSet \ Enum pour trouver tous les pilotes qui prennent en charge le GUID du port série. J'ai le sentiment que c'est ce que le gestionnaire de périphériques fait. Dans le cas où quelqu'un est intéressé, mon fragment de code peut être vu ci-dessous:

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

Autres conseils

Il est plus d'une question sur la question. Lorsque vous appelez la fonction première arg vous passez devrait être DeviceInfoSet que vous avez probablement de la Structure de SP_DEVICE_INTERFACE_DETAIL_DATA. Cela ne fournirait pas un moyen d'obtenir le nom convivial du périphérique. Je crois plutôt que vous souhaitez que l'instance de l'appareil.

D'après ce que j'ai lu, l'interface de l'appareil est utilisé comme un moyen d'obtenir le chemin de l'appareil qui peut être utilisé pour écrire.

Une chose que je l'ai fait pour tester votre code a été l'essayer à nouveau l'interface de périphérique de disque. J'ai fait quelques changements pour l'obtenir pour travailler sur mon système et il est pas encore tout à fait terminé. Je pense que le seul problème (probablement plus) est que je dois redimensionner la variable DevicePath inbetween les appels SetupDiGetDeviceInterfaceDetail.

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);
}

En outre, dans l'INF, vous devrez peut-être ajouter le AddInterface directive pour associer votre pilote avec l'interface correcte.

Je ne suis pas sûr que le correctif suivant résoudre votre problème comme indiqué dans

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

Un point de plus interessant: GUID_CLASS_COMPORT est obsolète à partir Win2000 partir ..

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

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

Un autre site que je trouve avoir 9 façons différentes de dénombrement. Bonne chance.

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

Vous dites que votre appareil est présent et accessible, mais vous accédez à votre appareil directement ou accédez-vous à un port par nom et numéro COMn:

J'ai un WinModem qui est connecté à mon pilote audio. Je n'ai pas de port série, même pas une simulation.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top