Gather Information from the Device Setup or Information Class
using System; using System.Collections.Generic; using System.ComponentModel; using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Text; public class SetupDi { /// <summary> /// Class Names (Incomplete??) /// </summary> public string[] ClassNames = { "AudioEndpoint", "CDROM", "Computer", "DiskDrive", "Display", "DriverInterface", "HDC", "HIDClass", "Keyboard", "MEDIA", "Monitor", "Mouse", "Net", "PrintQueue", "Processor", "SCSIAdapter", "Sensor", "SoftwareDevice", "System", "USB", "Volume", "VolumeSnapshot", "WPD" }; /// <summary> /// Are we running using 64 or 32 bits /// </summary> public bool Is64Bit => IntPtr.Size == 8; /// <summary> /// 32 and 64 bit operations require differing offsets within the pointer return values /// </summary> public uint OffsetSize => Is64Bit ? 8u : 6u; /// <summary> /// Get a list of active drives on the PC. /// </summary> public IEnumerable<string> GetDriveReadyList => from driveInfo in DriveInfo.GetDrives() where driveInfo.IsReady select driveInfo.Name; /// <summary> /// Get a list of drive: letters and associated MountPoints for active drives. /// </summary> public Dictionary<string, string> LogicalDrives { get { var _logicalDrives = new Dictionary<string, string>(); foreach (var drive in GetDriveReadyList) { var sb = new StringBuilder(1024); if (NativeWin32.GetVolumeNameForVolumeMountPoint(drive, sb, sb.Capacity)) _logicalDrives.Add(drive.Replace("\\", ""), sb.ToString()); } return _logicalDrives; } } /// <summary> /// Get a list of Drive: -> Disk numbers and associated length and offset information /// </summary> public Dictionary<string, List<NativeWin32.DISK_EXTENT>> DiskNumbers { get { var _diskNumbers = new Dictionary<string, List<NativeWin32.DISK_EXTENT>>(); foreach (var ld in LogicalDrives) { var dkexts = new List<NativeWin32.DISK_EXTENT>(); var hFile = NativeWin32.CreateFile(@"\\.\" + ld.Key, NativeWin32.GENERIC_READ, NativeWin32.FILE_SHARE_READ | NativeWin32.FILE_SHARE_WRITE, IntPtr.Zero, NativeWin32.OPEN_EXISTING, 0, IntPtr.Zero); if (hFile == (IntPtr) NativeWin32.INVALID_HANDLE_VALUE) throw new Win32Exception(Marshal.GetLastWin32Error()); var size = 1024; var buffer = Marshal.AllocHGlobal(size); var alloced = buffer; var bytesReturned = 0; try { if (!NativeWin32.DeviceIoControl(hFile, NativeWin32.IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, IntPtr.Zero, 0, buffer, size, out bytesReturned, IntPtr.Zero)) { } } catch (Exception e) { var m = e.Message; } finally { NativeWin32.CloseHandle(hFile); } if (bytesReturned > 0) { var vde = new NativeWin32.VOLUME_DISK_EXTENTS(); var dextent = new NativeWin32.DISK_EXTENT(); Marshal.PtrToStructure(buffer, vde); buffer = new IntPtr(buffer.ToInt64() + Marshal.SizeOf(vde)); for (var i = 0; i < vde.NumberOfDiskExtents; i++) { dextent = (NativeWin32.DISK_EXTENT) Marshal.PtrToStructure(buffer, typeof(NativeWin32.DISK_EXTENT)); dkexts.Add(dextent); buffer = new IntPtr(buffer.ToInt64() + Marshal.SizeOf(dextent)); } } Marshal.FreeHGlobal(alloced); _diskNumbers.Add(ld.Key, dkexts); } return _diskNumbers; } } /// <summary> /// Associates a drive letter to its physical disk numbers using SetupDi API functions. /// </summary> /// <returns></returns> public Dictionary<string, VOLUME_INFO> GetVolumePaths() { var _volumepaths = new Dictionary<string, VOLUME_INFO>(); var classGuid = NativeWin32.GUID_DEVINTERFACE.GUID_DEVINTERFACE_VOLUME; var hDevInfo = NativeWin32.SetupDiGetClassDevs(ref classGuid, null, IntPtr.Zero, NativeWin32.DICFG.DEVICEINTERFACE | NativeWin32.DICFG.PRESENT); if (hDevInfo == (IntPtr) NativeWin32.INVALID_HANDLE_VALUE) throw new Exception("read hardware information error"); var devIndex = 0u; do { var dia = new NativeWin32.SP_DEVICE_INTERFACE_DATA(); dia.cbSize = (uint) Marshal.SizeOf(typeof(NativeWin32.SP_DEVICE_INTERFACE_DATA)); if (NativeWin32.SetupDiEnumDeviceInterfaces(hDevInfo, IntPtr.Zero, classGuid, devIndex, ref dia)) { var didd = new NativeWin32.SP_DEVICE_INTERFACE_DETAIL_DATA(); didd.cbSize = OffsetSize; var devInfoData = new NativeWin32.SP_DEVINFO_DATA(); devInfoData.cbSize = (uint) Marshal.SizeOf(typeof(NativeWin32.SP_DEVINFO_DATA)); uint nRequiredSize = 0; uint nBytes = 1024; if (NativeWin32.SetupDiGetDeviceInterfaceDetail(hDevInfo, ref dia, ref didd, nBytes, ref nRequiredSize, ref devInfoData)) { var sb = new StringBuilder(1024); if (NativeWin32.GetVolumeNameForVolumeMountPoint(didd.devicePath + @"\", sb, sb.Capacity)) { var cv = sb.ToString(); var di = new VOLUME_INFO(); foreach (var V in LogicalDrives) if (V.Value.IndexOf(cv, StringComparison.OrdinalIgnoreCase) != -1) { di.Drive = V.Key; di.VolumeMountPoint = cv; di.DevicePath = didd.devicePath; foreach (var de in DiskNumbers[V.Key]) { di.DiskNumbers.Add(de.DiskNumber); di.ExtentLengths.Add(de.ExtentLength); di.StartingOffsets.Add(de.StartingOffset); } _volumepaths.Add(di.Drive.Trim(), di); break; } } } else { throw new Win32Exception(Marshal.GetLastWin32Error()); } } else { break; } devIndex++; } while (true); NativeWin32.SetupDiDestroyDeviceInfoList(hDevInfo); return _volumepaths; } /// <summary> /// Retrieves a list of All devices installed starting at the base root /// </summary> public Dictionary<string, DEVICE_INFO> GetAllGUIDs() { var DevList = new Dictionary<string, DEVICE_INFO>(); var classGuid = Guid.Empty; var hDevInfo = NativeWin32.SetupDiGetClassDevs(ref classGuid, null, IntPtr.Zero, NativeWin32.DICFG.ALLCLASSES | NativeWin32.DICFG.PRESENT); if (hDevInfo == (IntPtr) NativeWin32.INVALID_HANDLE_VALUE) throw new Exception("read hardware information error"); var devIndex = 0; do { var devInfoData = new NativeWin32.SP_DEVINFO_DATA(); devInfoData.cbSize = (uint) Marshal.SizeOf(typeof(NativeWin32.SP_DEVINFO_DATA)); devInfoData.classGuid = Guid.Empty; devInfoData.devInst = 0; devInfoData.reserved = UIntPtr.Zero; if (!NativeWin32.SetupDiEnumDeviceInfo(hDevInfo, devIndex, ref devInfoData)) break; var di = new DEVICE_INFO(); di.Guid = $"{devInfoData.classGuid}"; di.ClassName = $"{GetClassNameFromGuid(devInfoData.classGuid)}"; di.Description = $"{GetClassDescriptionFromGuid(devInfoData.classGuid)}"; di.InstanceID = $"{GetDeviceInstanceId(hDevInfo, devInfoData)}"; di.DI_Capabilities = (NativeWin32.DeviceCapabilities) GetProperty(hDevInfo, devInfoData, (uint) NativeWin32.SPDRP.Capabilities, 0); di.FriendlyName = GetProperty(hDevInfo, devInfoData, (uint) NativeWin32.SPDRP.FriendlyName, null); di.ClassGuid = GetProperty(hDevInfo, devInfoData, (uint) NativeWin32.SPDRP.ClassGuid, null); di.HardwareId = GetProperty(hDevInfo, devInfoData, (uint) NativeWin32.SPDRP.HardwareId, null); di.Mfg = GetProperty(hDevInfo, devInfoData, (uint) NativeWin32.SPDRP.Mfg, null); di.EnumeratorName = GetProperty(hDevInfo, devInfoData, (uint) NativeWin32.SPDRP.EnumeratorName, null); if (!DevList.ContainsValue(di)) DevList.Add($"{devIndex}", di); devIndex++; } while (true); NativeWin32.SetupDiDestroyDeviceInfoList(hDevInfo); return DevList; } /// <summary> /// Get a list of all devices starting a a specified Guid base. /// </summary> public IEnumerable<DEVICE_INFO> GetGUIDGroup(string ClassName) { if (ClassNames.All(c => c.IndexOf(ClassName, StringComparison.OrdinalIgnoreCase) == -1)) throw new Exception("ClassName is Invalid."); var dl = GetAllGUIDs(); return dl.Values.Where(d => d.ClassName.IndexOf(ClassName, StringComparison.OrdinalIgnoreCase) != -1); } /// <summary> /// property is SPDRP type /// </summary> private static uint GetProperty(IntPtr deviceInfoSet, NativeWin32.SP_DEVINFO_DATA devInfoData, uint property, uint defaultValue) { var propertyRegDataType = 0u; var requiredSize = IntPtr.Zero; var propertyBufferSize = (uint) Marshal.SizeOf(typeof(uint)); var propertyBuffer = Marshal.AllocHGlobal((int) propertyBufferSize); if (!NativeWin32.SetupDiGetDeviceRegistryProperty(deviceInfoSet, ref devInfoData, property, propertyRegDataType, propertyBuffer, propertyBufferSize, requiredSize)) { var error = Marshal.GetLastWin32Error(); if (error != NativeWin32.ERROR_INVALID_DATA) throw new Win32Exception(error); return defaultValue; } var value = (uint) Marshal.PtrToStructure(propertyBuffer, typeof(uint)); Marshal.FreeHGlobal(propertyBuffer); return value; } /// <summary> /// property is SPDRP type /// </summary> private Guid GetProperty(IntPtr deviceInfoSet, NativeWin32.SP_DEVINFO_DATA devData, uint property, Guid defaultValue) { var propertyRegDataType = 0u; var requiredSize = IntPtr.Zero; var propertyBufferSize = (uint) Marshal.SizeOf(typeof(Guid)); var propertyBuffer = Marshal.AllocHGlobal((int) propertyBufferSize); if (!NativeWin32.SetupDiGetDeviceRegistryProperty(deviceInfoSet, ref devData, property, propertyRegDataType, propertyBuffer, propertyBufferSize, requiredSize)) { Marshal.FreeHGlobal(propertyBuffer); var error = Marshal.GetLastWin32Error(); if (error != NativeWin32.ERROR_INVALID_DATA) throw new Win32Exception(error); return defaultValue; } var value = (Guid) Marshal.PtrToStructure(propertyBuffer, typeof(Guid)); Marshal.FreeHGlobal(propertyBuffer); return value; } /// <summary> /// property is SPDRP type /// </summary> private string GetProperty(IntPtr deviceInfoSet, NativeWin32.SP_DEVINFO_DATA devInfoData, uint property, string defaultValue) { var propertyRegDataType = 0u; var requiredSize = IntPtr.Zero; var propertyBufferSize = 1024u; var propertyBuffer = new StringBuilder((int) propertyBufferSize); if (!NativeWin32.SetupDiGetDeviceRegistryProperty(deviceInfoSet, ref devInfoData, property, propertyRegDataType, propertyBuffer, propertyBufferSize, requiredSize)) { var error = Marshal.GetLastWin32Error(); if (error != NativeWin32.ERROR_INVALID_DATA) throw new Win32Exception(error); return defaultValue; } return propertyBuffer.ToString(); } public string GetClassNameFromGuid(Guid guid) { var result = string.Empty; var className = new StringBuilder(); var iRequiredSize = 0; var iSize = 0; var b = NativeWin32.SetupDiClassNameFromGuid(ref guid, className, iSize, ref iRequiredSize); className = new StringBuilder(iRequiredSize); iSize = iRequiredSize; b = NativeWin32.SetupDiClassNameFromGuid(ref guid, className, iSize, ref iRequiredSize); if (b) result = className.ToString(); return result; } public string GetClassDescriptionFromGuid(Guid guid) { var result = string.Empty; var classDesc = new StringBuilder(0); var iRequiredSize = 0; var iSize = 0; var b = NativeWin32.SetupDiGetClassDescription(ref guid, classDesc, iSize, ref iRequiredSize); classDesc = new StringBuilder(iRequiredSize); iSize = iRequiredSize; b = NativeWin32.SetupDiGetClassDescription(ref guid, classDesc, iSize, ref iRequiredSize); if (b) result = classDesc.ToString(); return result; } public string GetDeviceInstanceId(IntPtr DeviceInfoSet, NativeWin32.SP_DEVINFO_DATA DeviceInfoData) { var result = string.Empty; var id = new StringBuilder(0); var iRequiredSize = 0; var iSize = 0; var b = NativeWin32.SetupDiGetDeviceInstanceId(DeviceInfoSet, ref DeviceInfoData, id, iSize, ref iRequiredSize); id = new StringBuilder(iRequiredSize); iSize = iRequiredSize; b = NativeWin32.SetupDiGetDeviceInstanceId(DeviceInfoSet, ref DeviceInfoData, id, iSize, ref iRequiredSize); if (b) result = id.ToString(); return result; } public class VOLUME_INFO { public string DevicePath; public List<uint> DiskNumbers = new List<uint>(); public string Drive; public List<ulong> ExtentLengths = new List<ulong>(); public List<ulong> StartingOffsets = new List<ulong>(); public string VolumeMountPoint; } public struct DEVICE_INFO { public string Guid; public string ClassName; public string Description; public string InstanceID; public NativeWin32.DeviceCapabilities DI_Capabilities; public string FriendlyName; public string ClassGuid; public string HardwareId; public string Mfg; public string EnumeratorName; public string Drive; public string VolumePath; } }