SetupDi.cs

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;
}
}
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; } }
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;
    }
}