/// <summary>
        /// Gets the property for SetupDiXXX function
        /// </summary>
        /// <param name="deviceHandle">The device handle.</param>
        /// <param name="deviceInformationData">The device information data.</param>
        /// <param name="property">The property.</param>
        /// <returns>String representation of the property</returns>
        internal static string GetProperty(IntPtr deviceHandle, SP_DEVINFO_DATA deviceInformationData, SetupDiGetDeviceRegistryPropertyEnum property)
        {
            bool functionAnswer = false;
            UInt32 propertyRegDataType = 0;
            IntPtr propertyBuffer = IntPtr.Zero;
            uint requireSize = 0;
            uint propertyMaximumSize = 1024;
            string actualData = string.Empty;

            try
            {
                propertyBuffer = Marshal.AllocHGlobal((int)propertyMaximumSize);

                functionAnswer = UnsafeNativeMethods.SetupDiGetDeviceRegistryProperty(deviceHandle,
                                                                                        ref deviceInformationData,
                                                                                        (uint)property,
                                                                                        out propertyRegDataType,
                                                                                        propertyBuffer,
                                                                                        propertyMaximumSize,
                                                                                        out requireSize);

                if (functionAnswer == false)
                {
                    if (Marshal.GetLastWin32Error() == UnsafeNativeMethods.ERROR_INVALID_DATA)
                    {
                        Marshal.ThrowExceptionForHR(UnsafeNativeMethods.ERROR_INVALID_DATA);
                    }
                }

                // We have the answer
                actualData = Marshal.PtrToStringAuto(propertyBuffer);
                return actualData;
            }
            catch (Exception exp_gen)
            {
                throw new Win32Exception("Could not receive property", exp_gen);
            }
            finally
            {
                if (propertyBuffer != IntPtr.Zero)
                    Marshal.FreeHGlobal(propertyBuffer);
            }
        }
        /// <summary>
        /// Gets the list of devices.
        /// </summary>
        /// <param name="token">The cancellation token.</param>
        /// <returns>List of detected devices</returns>
        /// <exception cref="System.ComponentModel.Win32Exception">
        /// Could not execute SetupDi functions
        /// </exception>
        protected IEnumerable<SystemDevice> GetListOfDevices(CancellationToken token)
        {
            List<SystemDevice> listOfDevices = new List<SystemDevice>();

            int flags = (int) (SetupDiGetClassDevsFlags.DIGCF_ALLCLASSES |SetupDiGetClassDevsFlags.DIGCF_DEVICEINTERFACE| SetupDiGetClassDevsFlags.DIGCF_PRESENT);
            Guid aquireGuid = Guid.Empty;

            IntPtr deviceHandle = UnsafeNativeMethods.SetupDiGetClassDevs(ref aquireGuid, IntPtr.Zero, IntPtr.Zero, flags);
            int win32Error = Marshal.GetLastWin32Error();
            if (deviceHandle.ToInt32() == UnsafeNativeMethods.INVALID_HANDLE_VALUE)
            {
                throw new Win32Exception("Could not execute SetupDi functions", new Win32Exception(win32Error));
            }

            SP_DEVICE_INTERFACE_DATA spDeviceInterfaceData = new SP_DEVICE_INTERFACE_DATA();
            spDeviceInterfaceData.cbSize = Marshal.SizeOf(typeof(SP_DEVICE_INTERFACE_DATA));

            Guid classGuid = SetupDiInterfacesGuid.GUID_DEVINTERFACE_DISK;
            uint memberIndex = 0;
            bool functionResult = false;

            do
            {
                token.ThrowIfCancellationRequested();

                functionResult = UnsafeNativeMethods.SetupDiEnumDeviceInterfaces(deviceHandle, IntPtr.Zero, ref classGuid, memberIndex, ref spDeviceInterfaceData);
                if (functionResult == false)
                {
                    int nativeError = Marshal.GetLastWin32Error();

                    UnsafeNativeMethods.SetupDiDestroyDeviceInfoList(deviceHandle);

                    if (nativeError == UnsafeNativeMethods.ERROR_NO_MORE_ITEMS)
                    {
                        // all done
                        break;
                    }
                    else
                    {
                        // Other error occurred
                        throw new Win32Exception("Error occurred while enumerating devices", new Win32Exception(Marshal.GetLastWin32Error()));
                    }
                }

                SP_DEVINFO_DATA spDevInfoData = new SP_DEVINFO_DATA();
                spDevInfoData.cbSize = Marshal.SizeOf(typeof(SP_DEVINFO_DATA));
                spDevInfoData.DevInst = 0;
                spDevInfoData.Reserved = IntPtr.Zero;

                SP_DEVICE_INTERFACE_DETAIL_DATA spDeviceInterfaceDetailedData = new SP_DEVICE_INTERFACE_DETAIL_DATA();
                if (IntPtr.Size == 8)
                {
                    // for 64 bit operating systems
                    spDeviceInterfaceDetailedData.cbSize = 8;
                }
                else
                {
                    // for 32 bit systems
                    spDeviceInterfaceDetailedData.cbSize = 4 + Marshal.SystemDefaultCharSize;
                }

                uint nRequiredSize = 0;
                uint bufferSize = 200;
                bool success = false;
                //
                // Should send twice - first time it's only return the 'nRequiredSize' value (but we already calculated it)
                success = UnsafeNativeMethods.SetupDiGetDeviceInterfaceDetail(deviceHandle,
                                                                                    ref spDeviceInterfaceData,
                                                                                    ref spDeviceInterfaceDetailedData,
                                                                                    bufferSize,
                                                                                    out nRequiredSize,
                                                                                    ref spDevInfoData);

                success = UnsafeNativeMethods.SetupDiGetDeviceInterfaceDetail(deviceHandle,
                                                                                ref spDeviceInterfaceData,
                                                                                ref spDeviceInterfaceDetailedData,
                                                                                nRequiredSize,
                                                                                out nRequiredSize,
                                                                                ref spDevInfoData);

                if (success == false)
                {
                //    // Still 'false' after sending twice
                //    UnsafeNativeMethods.SetupDiDestroyDeviceInfoList(deviceHandle);
                //    throw new Win32Exception("Could not receive details about device", new Win32Exception(Marshal.GetLastWin32Error()));
                }

                // Device
                listOfDevices.Add(new SystemDevice(spDeviceInterfaceDetailedData.DevicePath)
                {
                    FriendlyName = SetupDiGetDeviceProperty.GetProperty(deviceHandle, spDevInfoData, SetupDiGetDeviceRegistryPropertyEnum.SPDRP_FRIENDLYNAME),
                    DeviceClass = SetupDiGetDeviceProperty.GetProperty(deviceHandle, spDevInfoData, SetupDiGetDeviceRegistryPropertyEnum.SPDRP_CLASS)
                });

                // Next device
                memberIndex++;

            } while (true);

            deviceHandle = IntPtr.Zero;

            return listOfDevices;
        }
 internal static extern bool SetupDiGetDeviceRegistryProperty(IntPtr DeviceInfoSet,
                                                             ref SP_DEVINFO_DATA DeviceInfoData,
                                                             uint Property,
                                                             out UInt32 PropertyRegDataType,
                                                             IntPtr PropertyBuffer,
                                                             uint PropertyBufferSize,
                                                             out UInt32 RequiredSize);
 public static extern Boolean SetupDiGetDeviceInterfaceDetail(IntPtr hDevInfo,
                                                                ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData,
                                                                ref SP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData,
                                                                UInt32 deviceInterfaceDetailDataSize,
                                                                out UInt32 requiredSize,
                                                                ref SP_DEVINFO_DATA deviceInfoData);