Skip to content

Instantly share code, notes, and snippets.

@emoacht
Created April 30, 2024 20:48
Show Gist options
  • Save emoacht/935d391b22839f3454ca535dcfe953d0 to your computer and use it in GitHub Desktop.
Save emoacht/935d391b22839f3454ca535dcfe953d0 to your computer and use it in GitHub Desktop.
Show disk drives. This is slightly modified version of https://gist.github.com/emoacht/0afa084cf30123f121492ab26fb8174d
using System.Runtime.InteropServices;
using System.Text;
class Program
{
static void Main(string[] args)
{
ShowDiskDrives();
}
#region Win32
[DllImport("SetupAPI.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern nint SetupDiGetClassDevs(
[MarshalAs(UnmanagedType.LPStruct), In] Guid ClassGuid,
nint Enumerator,
nint hwndParent,
DIGCF Flags);
[Flags]
private enum DIGCF : uint
{
DIGCF_DEFAULT = 0x00000001,
DIGCF_PRESENT = 0x00000002,
DIGCF_ALLCLASSES = 0x00000004,
DIGCF_PROFILE = 0x00000008,
DIGCF_DEVICEINTERFACE = 0x00000010,
}
[DllImport("SetupAPI.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetupDiEnumDeviceInfo(
nint DeviceInfoSet,
uint MemberIndex,
ref SP_DEVINFO_DATA DeviceInfoData);
[StructLayout(LayoutKind.Sequential)]
private struct SP_DEVINFO_DATA
{
public uint cbSize;
public Guid ClassGuid;
public uint DevInst;
public nint Reserved;
}
[DllImport("SetupAPI.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetupDiDestroyDeviceInfoList(nint DeviceInfoSet);
[DllImport("SetupAPI.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetupDiGetDeviceRegistryProperty(
nint DeviceInfoSet,
ref SP_DEVINFO_DATA DeviceInfoData,
SPDRP Property,
nint PropertyRegDataType,
nint PropertyBuffer,
uint PropertyBufferSize,
out uint RequiredSize);
private enum SPDRP : uint
{
SPDRP_DEVICEDESC = 0x00000000,
SPDRP_HARDWAREID = 0x00000001,
SPDRP_COMPATIBLEIDS = 0x00000002,
SPDRP_SERVICE = 0x00000004,
SPDRP_CLASS = 0x00000007,
SPDRP_CLASSGUID = 0x00000008,
SPDRP_DRIVER = 0x00000009,
SPDRP_CONFIGFLAGS = 0x0000000A,
SPDRP_MFG = 0x0000000B,
SPDRP_FRIENDLYNAME = 0x0000000C,
SPDRP_LOCATION_INFORMATION = 0x0000000D,
SPDRP_PHYSICAL_DEVICE_OBJECT_NAME = 0x0000000E,
SPDRP_CAPABILITIES = 0x0000000F,
SPDRP_UI_NUMBER = 0x00000010,
SPDRP_UPPERFILTERS = 0x00000011,
SPDRP_LOWERFILTERS = 0x00000012,
SPDRP_BUSTYPEGUID = 0x00000013,
SPDRP_LEGACYBUSTYPE = 0x00000014,
SPDRP_BUSNUMBER = 0x00000015,
SPDRP_ENUMERATOR_NAME = 0x00000016,
SPDRP_SECURITY = 0x00000017,
SPDRP_SECURITY_SDS = 0x00000018,
SPDRP_DEVTYPE = 0x00000019,
SPDRP_EXCLUSIVE = 0x0000001A,
SPDRP_CHARACTERISTICS = 0x0000001B,
SPDRP_ADDRESS = 0x0000001C,
SPDRP_UI_NUMBER_DESC_FORMAT = 0X0000001D,
SPDRP_DEVICE_POWER_DATA = 0x0000001E,
SPDRP_REMOVAL_POLICY = 0x0000001F,
SPDRP_REMOVAL_POLICY_HW_DEFAULT = 0x00000020,
SPDRP_REMOVAL_POLICY_OVERRIDE = 0x00000021,
SPDRP_INSTALL_STATE = 0x00000022,
SPDRP_LOCATION_PATHS = 0x00000023
}
[Flags]
private enum CM_DEVCAP : uint
{
CM_DEVCAP_LOCKSUPPORTED = 0x00000001,
CM_DEVCAP_EJECTSUPPORTED = 0x00000002,
CM_DEVCAP_REMOVABLE = 0x00000004,
CM_DEVCAP_DOCKDEVICE = 0x00000008,
CM_DEVCAP_UNIQUEID = 0x00000010,
CM_DEVCAP_SILENTINSTALL = 0x00000020,
CM_DEVCAP_RAWDEVICEOK = 0x00000040,
CM_DEVCAP_SURPRISEREMOVALOK = 0x00000080,
CM_DEVCAP_HARDWAREDISABLED = 0x00000100,
CM_DEVCAP_NONDYNAMIC = 0x00000200
}
[DllImport("Setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetupDiGetDeviceInstanceId(
nint DeviceInfoSet,
ref SP_DEVINFO_DATA DeviceInfoData,
[Out] StringBuilder DeviceInstanceId,
uint DeviceInstanceIdSize,
out uint RequiredSize);
private const int INVALID_HANDLE_VALUE = -1;
private const int ERROR_NO_MORE_ITEMS = 259;
#endregion
private readonly static Guid DiskDriveClassGuid = new Guid("{4d36e967-e325-11ce-bfc1-08002be10318}");
public static void ShowDiskDrives()
{
int index = 0;
EnumerateDiskDrives((deviceInfoSet, deviceInfoData) =>
{
Console.WriteLine(@$"/// {index++} ///");
Console.WriteLine($"DeviceInstanceId: {GetDeviceInstanceId(deviceInfoSet, deviceInfoData)}");
Console.WriteLine($"HardwareId: {GetDevicePropertyString(deviceInfoSet, deviceInfoData, SPDRP.SPDRP_HARDWAREID)}");
Console.WriteLine($"FriendlyName: {GetDevicePropertyString(deviceInfoSet, deviceInfoData, SPDRP.SPDRP_FRIENDLYNAME)}");
var capabilities = (CM_DEVCAP)GetDevicePropertyUInt(deviceInfoSet, deviceInfoData, SPDRP.SPDRP_CAPABILITIES);
Console.WriteLine($"IsRemovable: {capabilities.HasFlag(CM_DEVCAP.CM_DEVCAP_REMOVABLE)} ({capabilities})");
return "";
}).ToArray();
}
private static IEnumerable<T> EnumerateDiskDrives<T>(Func<nint, SP_DEVINFO_DATA, T> convert)
{
var deviceInfoSet = nint.Zero;
try
{
deviceInfoSet = SetupDiGetClassDevs(
DiskDriveClassGuid,
nint.Zero,
nint.Zero,
DIGCF.DIGCF_PRESENT);
if (deviceInfoSet == INVALID_HANDLE_VALUE)
yield break;
uint index = 0;
while (true)
{
var deviceInfoData = new SP_DEVINFO_DATA { cbSize = (uint)Marshal.SizeOf<SP_DEVINFO_DATA>() };
if (SetupDiEnumDeviceInfo(
deviceInfoSet,
index,
ref deviceInfoData))
{
yield return convert.Invoke(deviceInfoSet, deviceInfoData);
}
else if (Marshal.GetLastWin32Error() == ERROR_NO_MORE_ITEMS)
{
yield break;
}
index++;
}
}
finally
{
if (deviceInfoSet != nint.Zero)
SetupDiDestroyDeviceInfoList(deviceInfoSet);
}
}
private static string GetDevicePropertyString(nint DeviceInfoSet, SP_DEVINFO_DATA DeviceInfoData, SPDRP property)
{
return GetDevicePropertyValue(DeviceInfoSet, DeviceInfoData, property, (pointer, _) => Marshal.PtrToStringAuto(pointer));
}
private static uint GetDevicePropertyUInt(nint DeviceInfoSet, SP_DEVINFO_DATA DeviceInfoData, SPDRP property)
{
return GetDevicePropertyValue(DeviceInfoSet, DeviceInfoData, property, (pointer, size) =>
{
var array = new byte[size];
Marshal.Copy(pointer, array, 0, (int)size);
return BitConverter.ToUInt32(array, 0);
});
}
private static T GetDevicePropertyValue<T>(nint DeviceInfoSet, SP_DEVINFO_DATA DeviceInfoData, SPDRP property, Func<nint, uint, T> convert)
{
SetupDiGetDeviceRegistryProperty(
DeviceInfoSet,
ref DeviceInfoData,
property,
nint.Zero,
nint.Zero,
0,
out uint requiredSize);
var buffer = nint.Zero;
try
{
buffer = Marshal.AllocHGlobal((int)requiredSize);
if (SetupDiGetDeviceRegistryProperty(
DeviceInfoSet,
ref DeviceInfoData,
property,
nint.Zero,
buffer,
requiredSize,
out _))
{
return convert.Invoke(buffer, requiredSize);
}
return default;
}
finally
{
if (buffer != nint.Zero)
Marshal.FreeHGlobal(buffer);
}
}
private static string GetDeviceInstanceId(nint DeviceInfoSet, SP_DEVINFO_DATA DeviceInfoData)
{
SetupDiGetDeviceInstanceId(
DeviceInfoSet,
ref DeviceInfoData,
null,
0,
out uint requiredSize);
var buffer = new StringBuilder((int)requiredSize);
if (SetupDiGetDeviceInstanceId(
DeviceInfoSet,
ref DeviceInfoData,
buffer,
requiredSize,
out _))
{
return buffer.ToString();
}
return default;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment