/// <summary>
        /// Gets a device handle from matching.
        /// </summary>
        /// <param name="deviceInformation">The device information.</param>
        /// <param name="deviceInfoSet">The device info set.</param>
        /// <param name="deviceInfoData">The device info data.</param>
        private static void GetDeviceHandleFromMatch(
            DeviceInformation deviceInformation,
            out IntPtr deviceInfoSet,
            out SP_DEVINFO_DATA deviceInfoData)
        {
            Guid emptyGuid = Guid.Empty;

            deviceInfoSet = Win32SetupApi.SetupDiGetClassDevs(
                ref emptyGuid,
                IntPtr.Zero,
                IntPtr.Zero,
                (int)DIGCF.DIGCF_PRESENT | (int)DIGCF.DIGCF_ALLCLASSES);

            deviceInfoData      = new SP_DEVINFO_DATA();
            deviceInfoData.Size = Marshal.SizeOf(typeof(SP_DEVINFO_DATA));

            for (int i = 0; Win32SetupApi.SetupDiEnumDeviceInfo(deviceInfoSet, i, ref deviceInfoData); i++)
            {
                String matchSubjectDesc        = GetDescription(deviceInfoSet, deviceInfoData);
                String matchSubjectPhysDevName = GetPhysicalDeviceObjectName(deviceInfoSet, deviceInfoData);
                int    matchSubjectBus         = GetBusNumber(deviceInfoSet, deviceInfoData);

                if (
                    deviceInformation.Description.Equals(matchSubjectDesc) &&
                    deviceInformation.BusNumber.Equals(matchSubjectBus) &&
                    deviceInformation.PhysicalDeviceObjectName.Equals(matchSubjectPhysDevName))
                {
                    return;
                }
            }

            deviceInfoData = new SP_DEVINFO_DATA();
            deviceInfoSet  = IntPtr.Zero;
        }
        /// <summary>
        /// Gets a list of devices that match the filter criteria.
        /// </summary>
        /// <param name="deviceFilter">The device filter.</param>
        /// <returns>An array of DeviceInformation objects.</returns>
        public static DeviceInformation[] GetDevices(DeviceFilter deviceFilter)
        {
            List <DeviceInformation> result = new List <DeviceInformation>();

            Guid emptyGuid = Guid.Empty;

            int filter;

            if (deviceFilter == DeviceFilter.AllDevices || deviceFilter == DeviceFilter.AllPciDevices)
            {
                filter = (int)DIGCF.DIGCF_ALLCLASSES;
            }
            else
            {
                filter = (int)DIGCF.DIGCF_ALLCLASSES | (int)DIGCF.DIGCF_PRESENT;
            }

            IntPtr deviceInfoSet =
                Win32SetupApi.SetupDiGetClassDevs(
                    ref emptyGuid,
                    IntPtr.Zero,
                    IntPtr.Zero,
                    filter);

            SP_DEVINFO_DATA deviceInfoData =
                new SP_DEVINFO_DATA();

            deviceInfoData.Size = Marshal.SizeOf(typeof(SP_DEVINFO_DATA));

            for (int i = 0; Win32SetupApi.SetupDiEnumDeviceInfo(deviceInfoSet, i, ref deviceInfoData); i++)
            {
                DeviceInformation deviceInformation =
                    GetDeviceInformation(deviceInfoSet, deviceInfoData);

                switch (deviceFilter)
                {
                case DeviceFilter.PresentPciDevices:
                case DeviceFilter.AllPciDevices:
                    if (!deviceInformation.LocationInfo
                        .ToLowerInvariant().Contains("pci"))
                    {
                        continue; // relates to the for-loop
                    }
                    else
                    {
                        break; // relates to the switch
                    }

                case DeviceFilter.AllDevices:
                default:
                    break;
                }

                result.Add(deviceInformation);
            }

            Win32SetupApi.SetupDiDestroyDeviceInfoList(deviceInfoSet);

            return(result.ToArray());
        }
        /// <summary>
        /// Gets the matching drivers for a device.
        /// </summary>
        /// <param name="devInfoSet">The device info set.</param>
        /// <param name="devInfoData">The device info data.</param>
        /// <returns>An array of matching device drivers.</returns>
        private static DriverInstance[] GetMatchingDrivers(
            IntPtr devInfoSet,
            SP_DEVINFO_DATA devInfoData)
        {
            List <DriverInstance> result = null;

            SP_DRVINFO_DATA drvInfoData = new SP_DRVINFO_DATA();

            drvInfoData.Size = Marshal.SizeOf(typeof(SP_DRVINFO_DATA));
            if (Win32SetupApi.SetupDiBuildDriverInfoList(devInfoSet, ref devInfoData, Constants.SPDIT_COMPATDRIVER))
            {
                result = new List <DriverInstance>();

                for (int i = 0; Win32SetupApi.SetupDiEnumDriverInfo(devInfoSet, ref devInfoData, Constants.SPDIT_COMPATDRIVER, i, ref drvInfoData); i++)
                {
                    result.Add(new DriverInstance
                    {
                        Description      = drvInfoData.Description,
                        Version          = drvInfoData.DriverVersion,
                        ManufacturerName = drvInfoData.MfgName,
                        ProviderName     = drvInfoData.ProviderName,
                        DriverDate       = drvInfoData.DriverDate.ToDateTime()
                    });
                }
            }

            return(result != null?result.ToArray() : new DriverInstance[]
            {
            });
        }
        /// <summary>
        /// Gets a device's registry property. Helper class that
        /// encapsulates the core functionality of the other get
        /// registry property functions.
        /// </summary>
        /// <param name="devInfoSet">The dev info set.</param>
        /// <param name="devInfoData">The dev info data.</param>
        /// <param name="propertyIndex">Index of the property.</param>
        /// <returns>The property buffer.</returns>
        private static StringBuilder GetProperty(
            IntPtr devInfoSet,
            SP_DEVINFO_DATA devInfoData,
            SPDRP propertyIndex)
        {
            Int32         requiredSize        = 0;
            Int32         propertyRegDataType = 0;
            StringBuilder propertyBuffer;

            Win32SetupApi.SetupDiGetDeviceRegistryProperty(
                devInfoSet,
                ref devInfoData,
                (int)propertyIndex,
                ref propertyRegDataType,
                null,
                0,
                ref requiredSize);

            propertyBuffer = new StringBuilder(requiredSize);

            propertyRegDataType = 0;
            Win32SetupApi.SetupDiGetDeviceRegistryProperty(
                devInfoSet,
                ref devInfoData,
                (int)propertyIndex,
                ref propertyRegDataType,
                propertyBuffer,
                propertyBuffer.Capacity,
                ref requiredSize);

            return(propertyBuffer);
        }
        /// <summary>
        /// Applies the specified driver to the specified device.
        /// </summary>
        /// <param name="deviceInfo">The device info.</param>
        /// <param name="driverInstance">The driver instance.</param>
        public static void ApplyDriverToDevice(
            DeviceInformation deviceInfo,
            DriverInstance driverInstance)
        {
            IntPtr          deviceInfoSet;
            SP_DEVINFO_DATA devInfoData;

            GetDeviceHandleFromMatch(deviceInfo, out deviceInfoSet, out devInfoData);

            SP_DRVINFO_DATA drvInfoData;

            GetDriverHandleFromMatch(driverInstance, deviceInfoSet, devInfoData, out drvInfoData);

            try
            {
                bool needReboot = false;
                Win32SetupApi.DiInstallDevice(
                    IntPtr.Zero,
                    deviceInfoSet,
                    ref devInfoData,
                    ref drvInfoData,
                    0,
                    ref needReboot);

                RebootRequired = needReboot;
            }
            catch (Exception)
            {
                throw;
            }
        }
        /// <summary>
        /// Uninstalls the device.
        /// </summary>
        /// <param name="deviceInfo">The device info.</param>
        public static void UninstallDevice(DeviceInformation deviceInfo)
        {
            IntPtr          hdevInfo;
            SP_DEVINFO_DATA devInfoData;

            GetDeviceHandleFromMatch(deviceInfo, out hdevInfo, out devInfoData);

            Boolean needReboot;

            Win32SetupApi.DiUninstallDevice(
                IntPtr.Zero,
                hdevInfo,
                devInfoData,
                0,
                out needReboot);

            RebootRequired = needReboot;
        }
        /// <summary>
        /// Gets a driver handle from matching.
        /// </summary>
        /// <param name="driverInstance">The driver instance.</param>
        /// <param name="deviceInfoSet">The device info set.</param>
        /// <param name="deviceInfoData">The device info data.</param>
        /// <param name="drvInfoData">The DRV info data.</param>
        private static void GetDriverHandleFromMatch(
            DriverInstance driverInstance,
            IntPtr deviceInfoSet,
            SP_DEVINFO_DATA deviceInfoData,
            out SP_DRVINFO_DATA drvInfoData)
        {
            drvInfoData      = new SP_DRVINFO_DATA();
            drvInfoData.Size = Marshal.SizeOf(typeof(SP_DRVINFO_DATA));
            if (Win32SetupApi.SetupDiBuildDriverInfoList(deviceInfoSet, ref deviceInfoData, Constants.SPDIT_COMPATDRIVER))
            {
                for (int i = 0; Win32SetupApi.SetupDiEnumDriverInfo(deviceInfoSet, ref deviceInfoData, Constants.SPDIT_COMPATDRIVER, i, ref drvInfoData); i++)
                {
                    if (driverInstance.Description.Equals(drvInfoData.Description))
                    {
                        return;
                    }
                }
            }

            drvInfoData = new SP_DRVINFO_DATA();
            return;
        }