Create a gist now

Instantly share code, notes, and snippets.

Embed
What would you like to do?
C# SetupDi API Enumerate Device Chain
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 = 0;
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, (uint) 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;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment