如何从供应商/产品ID获取USB驱动器的驱动器号?

时间:2019-05-10 18:46:11

标签: c# usb

我只知道USB驱动器的供应商和产品ID,但我需要能够获取与此设备关联的所有驱动器号。

System.IO.DriveInfo没有提供可以找到vid / pid的任何ID。

LibUsb包装器存在相反的问题-大量的id信息,但是我无法连接到安装点。

2 个答案:

答案 0 :(得分:1)

这是一个对我有用的解决方案,为您提供与您的供应商和产品ID匹配的所有驱动器。并不是所有的代码都是我写的。

#include <windows.h>
#include <stdio.h>
#include <setupapi.h>
#include <cfgmgr32.h>
#include <winioctl.h>

#define BUFFER_SIZE 256
#define MAX_DRIVES 26

// Finds the device interface for the CDROM drive with the given interface number.
DEVINST GetDrivesDevInstByDeviceNumber(long DeviceNumber)
{
   const GUID *guid = &GUID_DEVINTERFACE_DISK;

   // Get device interface info set handle
   // for all devices attached to system
   HDEVINFO hDevInfo = SetupDiGetClassDevs(guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
   if (hDevInfo == INVALID_HANDLE_VALUE)
      return 0;

   // Retrieve a context structure for a device interface of a device information set.
   BYTE buf[1024];
   PSP_DEVICE_INTERFACE_DETAIL_DATA pspdidd = (PSP_DEVICE_INTERFACE_DETAIL_DATA)buf;
   SP_DEVICE_INTERFACE_DATA spdid;
   SP_DEVINFO_DATA spdd;
   DWORD dwSize;

   spdid.cbSize = sizeof(spdid);

   // Iterate through all the interfaces and try to match one based on
   // the device number.
   for (DWORD i = 0; SetupDiEnumDeviceInterfaces(hDevInfo, NULL, guid, i, &spdid); i++)
   {
      // Get the device path.
      dwSize = 0;
      SetupDiGetDeviceInterfaceDetail(hDevInfo, &spdid, NULL, 0, &dwSize, NULL);
      if (dwSize == 0 || dwSize > sizeof(buf))
         continue;

      pspdidd->cbSize = sizeof(*pspdidd);
      ZeroMemory((PVOID)&spdd, sizeof(spdd));
      spdd.cbSize = sizeof(spdd);
      if (!SetupDiGetDeviceInterfaceDetail(hDevInfo, &spdid, pspdidd,
                                           dwSize, &dwSize, &spdd))
         continue;

      // Open the device.
      HANDLE hDrive = CreateFile(pspdidd->DevicePath, 0,
                                 FILE_SHARE_READ | FILE_SHARE_WRITE,
                                 NULL, OPEN_EXISTING, 0, NULL);
      if (hDrive == INVALID_HANDLE_VALUE)
         continue;

      // Get the device number.
      STORAGE_DEVICE_NUMBER sdn;
      dwSize = 0;
      if (DeviceIoControl(hDrive,
                          IOCTL_STORAGE_GET_DEVICE_NUMBER,
                          NULL, 0, &sdn, sizeof(sdn),
                          &dwSize, NULL))
      {
         // Does it match?
         if (DeviceNumber == (long)sdn.DeviceNumber)
         {
            CloseHandle(hDrive);
            SetupDiDestroyDeviceInfoList(hDevInfo);
            return spdd.DevInst;
         }
      }
      CloseHandle(hDrive);
   }

   SetupDiDestroyDeviceInfoList(hDevInfo);
   return 0;
}

// Returns true if the given device instance belongs to the USB device with the given VID and PID.
boolean matchDevInstToUsbDevice(DEVINST device, DWORD vid, DWORD pid)
{
   // This is the string we will be searching for in the device harware IDs.
   TCHAR hwid[64];
   sprintf(hwid, "VID_%04X&PID_%04X", vid, pid);

   // Get a list of hardware IDs for all USB devices.
   ULONG ulLen;
   CM_Get_Device_ID_List_Size(&ulLen, NULL, CM_GETIDLIST_FILTER_NONE);
   TCHAR *pszBuffer = malloc(sizeof(TCHAR) * ulLen);
   CM_Get_Device_ID_List(NULL, pszBuffer, ulLen, CM_GETIDLIST_FILTER_NONE);

   // Iterate through the list looking for our ID.
   for (LPTSTR pszDeviceID = pszBuffer; *pszDeviceID; pszDeviceID += _tcslen(pszDeviceID) + 1)
   {
      // Some versions of Windows have the string in upper case and other versions have it
      // in lower case so just make it all upper.
      for (int i = 0; pszDeviceID[i]; i++)
         pszDeviceID[i] = toupper(pszDeviceID[i]);

      if (_tcsstr(pszDeviceID, hwid))
      {
         // Found the device, now we want the grandchild device, which is the "generic volume"
         DEVINST MSDInst = 0;
         if (CR_SUCCESS == CM_Locate_DevNode(&MSDInst, pszDeviceID, CM_LOCATE_DEVNODE_NORMAL))
         {
            DEVINST DiskDriveInst = 0;
            if (CR_SUCCESS == CM_Get_Child(&DiskDriveInst, MSDInst, 0))
            {
               // Now compare the grandchild node against the given device instance.
               if (device == DiskDriveInst)
                  return TRUE;
            }
         }
      }
   }

   return FALSE;
}

int scan_drives(DWORD vid, DWORD pid)
{
   TCHAR caDrive[4] = TEXT("A:\\");
   TCHAR volume[BUFFER_SIZE];
   TCHAR volume_path_name[BUFFER_SIZE];
   DWORD dwDriveMask;

   int count = 0;

   // Get all drives in the system.
   dwDriveMask = GetLogicalDrives();

   if (dwDriveMask == 0)
   {
      printf("Error - GetLogicalDrives failed\n");
      return -1;
   }

   // Loop for all drives.
   for (int nLoopIndex = 0; nLoopIndex < MAX_DRIVES; nLoopIndex++, dwDriveMask >>= 1)
   {
      // If a drive is present,
      if (dwDriveMask & 1)
      {
         caDrive[0] = TEXT('A') + nLoopIndex;

         // If a drive is removable.
         if (GetDriveType(caDrive) == DRIVE_REMOVABLE)
         {
            //Get its volume info.
            if (GetVolumeNameForVolumeMountPoint(caDrive, volume, BUFFER_SIZE))
            {
               DWORD lpcchReturnLength;

               GetVolumePathNamesForVolumeName(volume, volume_path_name, BUFFER_SIZE, &lpcchReturnLength);

               char szVolumeAccessPath[] = "\\\\.\\X:";
               szVolumeAccessPath[4] = caDrive[0];

               long DeviceNumber = -1;

               HANDLE hVolume = CreateFile(szVolumeAccessPath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);

               if (hVolume == INVALID_HANDLE_VALUE)
               {
                  return 1;
               }

               STORAGE_DEVICE_NUMBER sdn;
               DWORD dwBytesReturned = 0;

               long res = DeviceIoControl(hVolume, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &sdn, sizeof(sdn), &dwBytesReturned, NULL);

               if (res)
               {
                  DeviceNumber = sdn.DeviceNumber;
               }

               CloseHandle(hVolume);

               if (DeviceNumber != -1)
               {
                  DEVINST DevInst = GetDrivesDevInstByDeviceNumber(DeviceNumber);

                  boolean match = matchDevInstToUsbDevice(DevInst, vid, pid);

                  if (match)
                  {
                     printf("%s\t0x%04x\t0x%04x\n", volume_path_name, vid, pid);
                  }
               }

               count++;
            }
         }
      }
   }

   return count;
}

int main(int argc, char *argv[])
{

   if (argc > 1)
   {

      if (argc % 2 == 0)
      {
         return -1;
      }

      for (int i = 1; i < argc - 1; i += 2)
      {
         int vid, pid;

         sscanf(argv[i], "%x", &vid);
         sscanf(argv[i + 1], "%x", &pid);

         scan_drives(vid, pid);
      }
   }

   return 0;
}

答案 1 :(得分:0)

几年前有一个related post

我修改了答案的代码:

static void Main(string[] args)
{
    //  example call
    string device = FindPath("VID_0781&PID_5583");

    GetDriveLetter(device); 
}

static public string FindPath(string pattern)
{
    var USBobjects = new List<string>();
    string Entity = "*none*";

    foreach (ManagementObject entity in new ManagementObjectSearcher(
             $"select * from Win32_USBHub Where DeviceID Like '%{pattern}%'").Get())
    {
        Entity = entity["DeviceID"].ToString();

        foreach (ManagementObject controller in entity.GetRelated("Win32_USBController"))
        {
            foreach (ManagementObject obj in new ManagementObjectSearcher(
                     "ASSOCIATORS OF {Win32_USBController.DeviceID='" 
                     + controller["PNPDeviceID"].ToString() + "'}").Get())
            {
                if (obj.ToString().Contains("DeviceID"))
                    USBobjects.Add(obj["DeviceID"].ToString());

            }
        }
    }

    int VidPidposition = USBobjects.IndexOf(Entity);
    for (int i = VidPidposition; i <= USBobjects.Count; i++)
    {
        if (USBobjects[i].Contains("USBSTOR"))
        {
            return USBobjects[i];
        }
    }

    return "*none*";
}

public static void GetDriveLetter(string device)
{
    int driveCount = 0;

    foreach (ManagementObject drive in new ManagementObjectSearcher("select * from Win32_DiskDrive").Get())
    {
        if (drive["PNPDeviceID"].ToString() == device)
        {
            foreach (ManagementObject o in drive.GetRelated("Win32_DiskPartition"))
            {
                foreach (ManagementObject i in o.GetRelated("Win32_LogicalDisk"))
                {
                    Console.WriteLine("Disk: " + i["Name"].ToString());
                    driveCount++;
                }
            }
        }
    }

    if (driveCount == 0)
    {
        Console.WriteLine("No drive identified!");
    }
}

一些错误处理和优化很有意义。