Created
April 30, 2024 20:48
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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