How to detect nonpresent devices using C#

3.2k views Asked by At

My program (which is completely written in C#) has a use case in which the program will need to detect that a specific usb device is installed in the computer. In the case that the usb device is connected, WMI will solve this problem.

However in the case that the device is not connected (nonpresent device), then WMI will not be able to help. I am aware that setupdi will possibly help to resolve this issue, however I am not entirely familiar with C++ and the additional effort to add a marshalling function is quite significant, due to compliance with existing parts of the code.

Hence my question will be whether there is an equivalent c# way to detect the nonpresent devices in the system? I have also tried the registry search method, however the driver is a generic USB driver under HKLM\System\CurrentControlSet\services\WinUSB, and there is no additional information that can be used to identify that the usb driver is corresponding to the specific device we are interested in.

Another possible identifying information is the "Driver Provider" information in the Driver tab in Device manager. The usb device has quite a specific driver provider information that can be used to identify the device. However I do not know the existing API to retrieve this information.

Thank you very much for your assistance and looking forward for any possible solutions

2

There are 2 answers

1
RenniePet On BEST ANSWER

Don't know if this will help or not. It's a couple of snippets of code from something I wrote about 7 years ago, and haven't used since - the project was abandoned. Unfortunately, the whole USB-interfacing is about 700 lines of C# - too much to post here.

   /// <summary>
   /// This class represents a USB HID (Human Interface Device) device.
   /// </summary>
   public class UsbHidDevice : IDisposable
   {

      // The Windows GUID for HID USB devices
      private Guid _deviceClass;

      // The full "path name" of the device (set when found)
      private string _devicePath;


      #region Constructor

      public UsbHidDevice()
      {
         // Initialize the Windows GUID for HID devices
         Win32API.HidD_GetHidGuid(out _deviceClass);
      }

      #endregion Constructor


      /// <summary>
      /// Function to search the USB devices to see if the desired one is online.
      /// </summary>
      /// <param name="vendorId">vendor ID, or zero if not significant</param>
      /// <param name="productId">product ID</param>
      public bool FindDevice(int vendorId, int productId)
      {
         string strSearch;

         // Build the path search string
         if (vendorId == 0)
            strSearch = string.Format("pid_{0:x4}", productId);
         else
            strSearch = string.Format("vid_{0:x4}&pid_{1:x4}", vendorId, productId);

         // Prepare to search the USB device table in Windows
         // This gets a list of all HID devices currently connected to the computer (InfoSet)
         IntPtr hInfoSet = Win32API.SetupDiGetClassDevs(ref _deviceClass, null, IntPtr.Zero, Win32API.DIGCF_DEVICEINTERFACE | Win32API.DIGCF_PRESENT);

         try
         {
            // Build up a device interface data block
            Win32API.DeviceInterfaceData oInterface = new Win32API.DeviceInterfaceData();
            oInterface.Size = Marshal.SizeOf(oInterface);

            // Now iterate through the InfoSet memory block assigned within Windows in the 
            //  call to SetupDiGetClassDevs to get device details for each device connected
            int nIndex = 0;

            // This gets the device interface information for a device at index 'nIndex' in the memory block
            while (Win32API.SetupDiEnumDeviceInterfaces(hInfoSet, 0, ref _deviceClass, (uint)nIndex, ref oInterface))
            {
               // Get the device path (see helper method 'GetDevicePath')
               string strDevicePath = GetDevicePath(hInfoSet, ref oInterface);

               // Do a string search, if we find the VID/PID string then we found our device
               if (!string.IsNullOrEmpty(strDevicePath) && strDevicePath.IndexOf(strSearch) >= 0)
               {
                  _devicePath = strDevicePath;
                  return true;
               }

               // If we get here, we didn't find our device. So move on to the next one.
               log.Debug("FindDevice() - Incorrect device found, keep searching." + strDevicePath);
               nIndex++;
            }
         }

         catch (Exception e)
         {
            log.Error("FindDevice() - Exception:", e);
         }

         finally
         {
            // Before we go, we have to free up the InfoSet memory reserved by SetupDiGetClassDevs
            Win32API.SetupDiDestroyDeviceInfoList(hInfoSet);
         }

         // Device not found
         return false;
      }

... other methods not included here
   }


   /// <summary>
   /// Definition of some Windows API stuff.
   /// 
   /// This is copied from "A USB HID Component for C#" (also called "Sniffer"), By "wimar"
   ///  http://www.codeproject.com/KB/cs/USB_HID.aspx
   /// </summary>
   internal class Win32API
   {
      // Used in SetupDiClassDevs to get devices present in the system
      public const int DIGCF_PRESENT = 0x02;

      // Used in SetupDiClassDevs to get device interface details
      public const int DIGCF_DEVICEINTERFACE = 0x10;


      /// <summary>
      /// Provides details about a single USB device
      /// 
      /// The field "Reserved" has been changed from int to UIntPtr based on information on web page
      /// http://www.codeproject.com/KB/cs/USB_HID.aspx, see message "Does not work on 64 bit Vista?".
      /// </summary>
      [StructLayout(LayoutKind.Sequential, Pack = 1)]
      public struct DeviceInterfaceData
      {
         public int Size;
         public Guid InterfaceClassGuid;
         public int Flags;
         public UIntPtr Reserved;
      }


      /// <summary>
      /// Gets the GUID that Windows uses to represent HID class devices
      /// </summary>
      /// <param name="gHid">An out parameter to take the Guid</param>
      [DllImport("hid.dll", SetLastError = true)]
      public static extern void HidD_GetHidGuid(out Guid gHid);
      /// <summary>
      /// Allocates an InfoSet memory block within Windows that contains details of devices.
      /// </summary>
      /// <param name="gClass">Class guid (e.g. HID guid)</param>
      /// <param name="strEnumerator">Not used</param>
      /// <param name="hParent">Not used</param>
      /// <param name="nFlags">Type of device details required (DIGCF_ constants)</param>
      /// <returns>A reference to the InfoSet</returns>
      [DllImport("setupapi.dll", SetLastError = true)]
      public static extern IntPtr SetupDiGetClassDevs(ref Guid gClass, [MarshalAs(UnmanagedType.LPStr)] string strEnumerator, IntPtr hParent, uint nFlags);


      /// <summary>
      /// Gets the DeviceInterfaceData for a device from an InfoSet.
      /// </summary>
      /// <param name="lpDeviceInfoSet">InfoSet to access</param>
      /// <param name="nDeviceInfoData">Not used</param>
      /// <param name="gClass">Device class guid</param>
      /// <param name="nIndex">Index into InfoSet for device</param>
      /// <param name="oInterfaceData">DeviceInterfaceData to fill with data</param>
      /// <returns>True if successful, false if not (e.g. when index is passed end of InfoSet)</returns>
      [DllImport("setupapi.dll", SetLastError = true)]
      public static extern bool SetupDiEnumDeviceInterfaces(IntPtr lpDeviceInfoSet, uint nDeviceInfoData, ref Guid gClass, uint nIndex, ref DeviceInterfaceData oInterfaceData);


      /// <summary>
      /// Frees InfoSet allocated in call to above.
      /// </summary>
      /// <param name="lpInfoSet">Reference to InfoSet</param>
      /// <returns>true if successful</returns>
      [DllImport("setupapi.dll", SetLastError = true)]
      public static extern int SetupDiDestroyDeviceInfoList(IntPtr lpInfoSet);

... other stuff missing
   }

As mentioned in a comment in the code, this is based on this: http://www.codeproject.com/Articles/18099/A-USB-HID-Component-for-C

I may have omitted some stuff that's needed - let me know.

3
erdemu On
        string ComputerName = "localhost";
        ManagementScope Scope;
        Scope = new ManagementScope(String.Format("\\\\{0}\\root\\CIMV2", ComputerName), null);

        Scope.Connect();

        string query = "SELECT * FROM Win32_PnPEntity Where ClassGuid = NULL";

        ObjectQuery Query = new ObjectQuery(query);

        ManagementObjectSearcher Searcher = new ManagementObjectSearcher(Scope, Query);

        foreach (ManagementObject WmiObject in Searcher.Get())
        {
            textBox1.Text += WmiObject["Name"] + "\r\n";
        }