{"id":208,"date":"2020-08-20T01:09:37","date_gmt":"2020-08-20T01:09:37","guid":{"rendered":"https:\/\/michaeljohnsteiner.com\/?p=208"},"modified":"2020-08-20T01:09:37","modified_gmt":"2020-08-20T01:09:37","slug":"setupdi-cs","status":"publish","type":"post","link":"https:\/\/michaeljohnsteiner.com\/index.php\/2020\/08\/20\/setupdi-cs\/","title":{"rendered":"SetupDi.cs"},"content":{"rendered":"\n<p>Gather Information from the Device Setup or Information Class<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">using System;\nusing System.Collections.Generic;\nusing System.ComponentModel;\nusing System.IO;\nusing System.Linq;\nusing System.Runtime.InteropServices;\nusing System.Text;\npublic class SetupDi\n{\n    \/\/\/ &lt;summary>\n    \/\/\/     Class Names (Incomplete??)\n    \/\/\/ &lt;\/summary>\n    public string[] ClassNames =\n    {\n        \"AudioEndpoint\",\n        \"CDROM\",\n        \"Computer\",\n        \"DiskDrive\",\n        \"Display\",\n        \"DriverInterface\",\n        \"HDC\",\n        \"HIDClass\",\n        \"Keyboard\",\n        \"MEDIA\",\n        \"Monitor\",\n        \"Mouse\",\n        \"Net\",\n        \"PrintQueue\",\n        \"Processor\",\n        \"SCSIAdapter\",\n        \"Sensor\",\n        \"SoftwareDevice\",\n        \"System\",\n        \"USB\",\n        \"Volume\",\n        \"VolumeSnapshot\",\n        \"WPD\"\n    };\n    \/\/\/ &lt;summary>\n    \/\/\/     Are we running using 64 or 32 bits\n    \/\/\/ &lt;\/summary>\n    public bool Is64Bit => IntPtr.Size == 8;\n    \/\/\/ &lt;summary>\n    \/\/\/     32 and 64 bit operations require differing offsets within the pointer return values\n    \/\/\/ &lt;\/summary>\n    public uint OffsetSize => Is64Bit ? 8u : 6u;\n    \/\/\/ &lt;summary>\n    \/\/\/     Get a list of active drives on the PC.\n    \/\/\/ &lt;\/summary>\n    public IEnumerable&lt;string> GetDriveReadyList => from driveInfo in DriveInfo.GetDrives() where driveInfo.IsReady select driveInfo.Name;\n    \/\/\/ &lt;summary>\n    \/\/\/     Get a list of drive: letters and associated MountPoints for active drives.\n    \/\/\/ &lt;\/summary>\n    public Dictionary&lt;string, string> LogicalDrives\n    {\n        get\n        {\n            var _logicalDrives = new Dictionary&lt;string, string>();\n            foreach (var drive in GetDriveReadyList)\n            {\n                var sb = new StringBuilder(1024);\n                if (NativeWin32.GetVolumeNameForVolumeMountPoint(drive, sb, sb.Capacity))\n                    _logicalDrives.Add(drive.Replace(\"\\\\\", \"\"), sb.ToString());\n            }\n            return _logicalDrives;\n        }\n    }\n    \/\/\/ &lt;summary>\n    \/\/\/     Get a list of Drive: -> Disk numbers and associated length and offset information\n    \/\/\/ &lt;\/summary>\n    public Dictionary&lt;string, List&lt;NativeWin32.DISK_EXTENT>> DiskNumbers\n    {\n        get\n        {\n            var _diskNumbers = new Dictionary&lt;string, List&lt;NativeWin32.DISK_EXTENT>>();\n            foreach (var ld in LogicalDrives)\n            {\n                var dkexts = new List&lt;NativeWin32.DISK_EXTENT>();\n                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);\n                if (hFile == (IntPtr) NativeWin32.INVALID_HANDLE_VALUE)\n                    throw new Win32Exception(Marshal.GetLastWin32Error());\n                var size          = 1024;\n                var buffer        = Marshal.AllocHGlobal(size);\n                var alloced       = buffer;\n                var bytesReturned = 0;\n                try\n                {\n                    if (!NativeWin32.DeviceIoControl(hFile, NativeWin32.IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, IntPtr.Zero, 0, buffer, size, out bytesReturned, IntPtr.Zero))\n                    {\n                    }\n                }\n                catch (Exception e)\n                {\n                    var m = e.Message;\n                }\n                finally\n                {\n                    NativeWin32.CloseHandle(hFile);\n                }\n                if (bytesReturned > 0)\n                {\n                    var vde     = new NativeWin32.VOLUME_DISK_EXTENTS();\n                    var dextent = new NativeWin32.DISK_EXTENT();\n                    Marshal.PtrToStructure(buffer, vde);\n                    buffer = new IntPtr(buffer.ToInt64() + Marshal.SizeOf(vde));\n                    for (var i = 0; i &lt; vde.NumberOfDiskExtents; i++)\n                    {\n                        dextent = (NativeWin32.DISK_EXTENT) Marshal.PtrToStructure(buffer, typeof(NativeWin32.DISK_EXTENT));\n                        dkexts.Add(dextent);\n                        buffer = new IntPtr(buffer.ToInt64() + Marshal.SizeOf(dextent));\n                    }\n                }\n                Marshal.FreeHGlobal(alloced);\n                _diskNumbers.Add(ld.Key, dkexts);\n            }\n            return _diskNumbers;\n        }\n    }\n    \/\/\/ &lt;summary>\n    \/\/\/     Associates a drive letter to its physical disk numbers using SetupDi API functions.\n    \/\/\/ &lt;\/summary>\n    \/\/\/ &lt;returns>&lt;\/returns>\n    public Dictionary&lt;string, VOLUME_INFO> GetVolumePaths()\n    {\n        var _volumepaths = new Dictionary&lt;string, VOLUME_INFO>();\n        var classGuid    = NativeWin32.GUID_DEVINTERFACE.GUID_DEVINTERFACE_VOLUME;\n        var hDevInfo     = NativeWin32.SetupDiGetClassDevs(ref classGuid, null, IntPtr.Zero, NativeWin32.DICFG.DEVICEINTERFACE | NativeWin32.DICFG.PRESENT);\n        if (hDevInfo == (IntPtr) NativeWin32.INVALID_HANDLE_VALUE)\n            throw new Exception(\"read hardware information error\");\n        var devIndex = 0u;\n        do\n        {\n            var dia = new NativeWin32.SP_DEVICE_INTERFACE_DATA();\n            dia.cbSize = (uint) Marshal.SizeOf(typeof(NativeWin32.SP_DEVICE_INTERFACE_DATA));\n            if (NativeWin32.SetupDiEnumDeviceInterfaces(hDevInfo, IntPtr.Zero, classGuid, devIndex, ref dia))\n            {\n                var didd = new NativeWin32.SP_DEVICE_INTERFACE_DETAIL_DATA();\n                didd.cbSize = OffsetSize;\n                var devInfoData = new NativeWin32.SP_DEVINFO_DATA();\n                devInfoData.cbSize = (uint) Marshal.SizeOf(typeof(NativeWin32.SP_DEVINFO_DATA));\n                uint nRequiredSize = 0;\n                uint nBytes        = 1024;\n                if (NativeWin32.SetupDiGetDeviceInterfaceDetail(hDevInfo, ref dia, ref didd, nBytes, ref nRequiredSize, ref devInfoData))\n                {\n                    var sb = new StringBuilder(1024);\n                    if (NativeWin32.GetVolumeNameForVolumeMountPoint(didd.devicePath + @\"\\\", sb, sb.Capacity))\n                    {\n                        var cv = sb.ToString();\n                        var di = new VOLUME_INFO();\n                        foreach (var V in LogicalDrives)\n                            if (V.Value.IndexOf(cv, StringComparison.OrdinalIgnoreCase) != -1)\n                            {\n                                di.Drive            = V.Key;\n                                di.VolumeMountPoint = cv;\n                                di.DevicePath       = didd.devicePath;\n                                foreach (var de in DiskNumbers[V.Key])\n                                {\n                                    di.DiskNumbers.Add(de.DiskNumber);\n                                    di.ExtentLengths.Add(de.ExtentLength);\n                                    di.StartingOffsets.Add(de.StartingOffset);\n                                }\n                                _volumepaths.Add(di.Drive.Trim(), di);\n                                break;\n                            }\n                    }\n                }\n                else\n                {\n                    throw new Win32Exception(Marshal.GetLastWin32Error());\n                }\n            }\n            else\n            {\n                break;\n            }\n            devIndex++;\n        } while (true);\n        NativeWin32.SetupDiDestroyDeviceInfoList(hDevInfo);\n        return _volumepaths;\n    }\n    \/\/\/ &lt;summary>\n    \/\/\/     Retrieves a list of All devices installed starting at the base root\n    \/\/\/ &lt;\/summary>\n    public Dictionary&lt;string, DEVICE_INFO> GetAllGUIDs()\n    {\n        var DevList   = new Dictionary&lt;string, DEVICE_INFO>();\n        var classGuid = Guid.Empty;\n        var hDevInfo  = NativeWin32.SetupDiGetClassDevs(ref classGuid, null, IntPtr.Zero, NativeWin32.DICFG.ALLCLASSES | NativeWin32.DICFG.PRESENT);\n        if (hDevInfo == (IntPtr) NativeWin32.INVALID_HANDLE_VALUE)\n            throw new Exception(\"read hardware information error\");\n        var devIndex = 0;\n        do\n        {\n            var devInfoData = new NativeWin32.SP_DEVINFO_DATA();\n            devInfoData.cbSize    = (uint) Marshal.SizeOf(typeof(NativeWin32.SP_DEVINFO_DATA));\n            devInfoData.classGuid = Guid.Empty;\n            devInfoData.devInst   = 0;\n            devInfoData.reserved  = UIntPtr.Zero;\n            if (!NativeWin32.SetupDiEnumDeviceInfo(hDevInfo, devIndex, ref devInfoData))\n                break;\n            var di = new DEVICE_INFO();\n            di.Guid            = $\"{devInfoData.classGuid}\";\n            di.ClassName       = $\"{GetClassNameFromGuid(devInfoData.classGuid)}\";\n            di.Description     = $\"{GetClassDescriptionFromGuid(devInfoData.classGuid)}\";\n            di.InstanceID      = $\"{GetDeviceInstanceId(hDevInfo, devInfoData)}\";\n            di.DI_Capabilities = (NativeWin32.DeviceCapabilities) GetProperty(hDevInfo, devInfoData, (uint) NativeWin32.SPDRP.Capabilities, 0);\n            di.FriendlyName    = GetProperty(hDevInfo, devInfoData, (uint) NativeWin32.SPDRP.FriendlyName,   null);\n            di.ClassGuid       = GetProperty(hDevInfo, devInfoData, (uint) NativeWin32.SPDRP.ClassGuid,      null);\n            di.HardwareId      = GetProperty(hDevInfo, devInfoData, (uint) NativeWin32.SPDRP.HardwareId,     null);\n            di.Mfg             = GetProperty(hDevInfo, devInfoData, (uint) NativeWin32.SPDRP.Mfg,            null);\n            di.EnumeratorName  = GetProperty(hDevInfo, devInfoData, (uint) NativeWin32.SPDRP.EnumeratorName, null);\n            if (!DevList.ContainsValue(di))\n                DevList.Add($\"{devIndex}\", di);\n            devIndex++;\n        } while (true);\n        NativeWin32.SetupDiDestroyDeviceInfoList(hDevInfo);\n        return DevList;\n    }\n    \/\/\/ &lt;summary>\n    \/\/\/     Get a list of all devices starting a a specified Guid base.\n    \/\/\/ &lt;\/summary>\n    public IEnumerable&lt;DEVICE_INFO> GetGUIDGroup(string ClassName)\n    {\n        if (ClassNames.All(c => c.IndexOf(ClassName, StringComparison.OrdinalIgnoreCase) == -1))\n            throw new Exception(\"ClassName is Invalid.\");\n        var dl = GetAllGUIDs();\n        return dl.Values.Where(d => d.ClassName.IndexOf(ClassName, StringComparison.OrdinalIgnoreCase) != -1);\n    }\n    \/\/\/ &lt;summary>\n    \/\/\/     property is SPDRP type\n    \/\/\/ &lt;\/summary>\n    private static uint GetProperty(IntPtr deviceInfoSet, NativeWin32.SP_DEVINFO_DATA devInfoData, uint property, uint defaultValue)\n    {\n        var propertyRegDataType = 0u;\n        var requiredSize        = IntPtr.Zero;\n        var propertyBufferSize  = (uint) Marshal.SizeOf(typeof(uint));\n        var propertyBuffer      = Marshal.AllocHGlobal((int) propertyBufferSize);\n        if (!NativeWin32.SetupDiGetDeviceRegistryProperty(deviceInfoSet, ref devInfoData, property, propertyRegDataType, propertyBuffer, propertyBufferSize, requiredSize))\n        {\n            var error = Marshal.GetLastWin32Error();\n            if (error != NativeWin32.ERROR_INVALID_DATA)\n                throw new Win32Exception(error);\n            return defaultValue;\n        }\n        var value = (uint) Marshal.PtrToStructure(propertyBuffer, typeof(uint));\n        Marshal.FreeHGlobal(propertyBuffer);\n        return value;\n    }\n    \/\/\/ &lt;summary>\n    \/\/\/     property is SPDRP type\n    \/\/\/ &lt;\/summary>\n    private Guid GetProperty(IntPtr deviceInfoSet, NativeWin32.SP_DEVINFO_DATA devData, uint property, Guid defaultValue)\n    {\n        var propertyRegDataType = 0u;\n        var requiredSize        = IntPtr.Zero;\n        var propertyBufferSize  = (uint) Marshal.SizeOf(typeof(Guid));\n        var propertyBuffer      = Marshal.AllocHGlobal((int) propertyBufferSize);\n        if (!NativeWin32.SetupDiGetDeviceRegistryProperty(deviceInfoSet, ref devData, property, propertyRegDataType, propertyBuffer, propertyBufferSize, requiredSize))\n        {\n            Marshal.FreeHGlobal(propertyBuffer);\n            var error = Marshal.GetLastWin32Error();\n            if (error != NativeWin32.ERROR_INVALID_DATA)\n                throw new Win32Exception(error);\n            return defaultValue;\n        }\n        var value = (Guid) Marshal.PtrToStructure(propertyBuffer, typeof(Guid));\n        Marshal.FreeHGlobal(propertyBuffer);\n        return value;\n    }\n    \/\/\/ &lt;summary>\n    \/\/\/     property is SPDRP type\n    \/\/\/ &lt;\/summary>\n    private string GetProperty(IntPtr deviceInfoSet, NativeWin32.SP_DEVINFO_DATA devInfoData, uint property, string defaultValue)\n    {\n        var propertyRegDataType = 0u;\n        var requiredSize        = IntPtr.Zero;\n        var propertyBufferSize  = 1024u;\n        var propertyBuffer      = new StringBuilder((int) propertyBufferSize);\n        if (!NativeWin32.SetupDiGetDeviceRegistryProperty(deviceInfoSet, ref devInfoData, property, propertyRegDataType, propertyBuffer, propertyBufferSize, requiredSize))\n        {\n            var error = Marshal.GetLastWin32Error();\n            if (error != NativeWin32.ERROR_INVALID_DATA)\n                throw new Win32Exception(error);\n            return defaultValue;\n        }\n        return propertyBuffer.ToString();\n    }\n    public string GetClassNameFromGuid(Guid guid)\n    {\n        var result        = string.Empty;\n        var className     = new StringBuilder();\n        var iRequiredSize = 0;\n        var iSize         = 0;\n        var b             = NativeWin32.SetupDiClassNameFromGuid(ref guid, className, iSize, ref iRequiredSize);\n        className = new StringBuilder(iRequiredSize);\n        iSize     = iRequiredSize;\n        b         = NativeWin32.SetupDiClassNameFromGuid(ref guid, className, iSize, ref iRequiredSize);\n        if (b)\n            result = className.ToString();\n        return result;\n    }\n    public string GetClassDescriptionFromGuid(Guid guid)\n    {\n        var result        = string.Empty;\n        var classDesc     = new StringBuilder(0);\n        var iRequiredSize = 0;\n        var iSize         = 0;\n        var b             = NativeWin32.SetupDiGetClassDescription(ref guid, classDesc, iSize, ref iRequiredSize);\n        classDesc = new StringBuilder(iRequiredSize);\n        iSize     = iRequiredSize;\n        b         = NativeWin32.SetupDiGetClassDescription(ref guid, classDesc, iSize, ref iRequiredSize);\n        if (b)\n            result = classDesc.ToString();\n        return result;\n    }\n    public string GetDeviceInstanceId(IntPtr DeviceInfoSet, NativeWin32.SP_DEVINFO_DATA DeviceInfoData)\n    {\n        var result        = string.Empty;\n        var id            = new StringBuilder(0);\n        var iRequiredSize = 0;\n        var iSize         = 0;\n        var b             = NativeWin32.SetupDiGetDeviceInstanceId(DeviceInfoSet, ref DeviceInfoData, id, iSize, ref iRequiredSize);\n        id    = new StringBuilder(iRequiredSize);\n        iSize = iRequiredSize;\n        b     = NativeWin32.SetupDiGetDeviceInstanceId(DeviceInfoSet, ref DeviceInfoData, id, iSize, ref iRequiredSize);\n        if (b)\n            result = id.ToString();\n        return result;\n    }\n    public class VOLUME_INFO\n    {\n        public string      DevicePath;\n        public List&lt;uint>  DiskNumbers = new List&lt;uint>();\n        public string      Drive;\n        public List&lt;ulong> ExtentLengths   = new List&lt;ulong>();\n        public List&lt;ulong> StartingOffsets = new List&lt;ulong>();\n        public string      VolumeMountPoint;\n    }\n    public struct DEVICE_INFO\n    {\n        public string                         Guid;\n        public string                         ClassName;\n        public string                         Description;\n        public string                         InstanceID;\n        public NativeWin32.DeviceCapabilities DI_Capabilities;\n        public string                         FriendlyName;\n        public string                         ClassGuid;\n        public string                         HardwareId;\n        public string                         Mfg;\n        public string                         EnumeratorName;\n        public string                         Drive;\n        public string                         VolumePath;\n    }\n}<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Gather Information from the Device Setup or Information Class<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[2],"tags":[109,110,111,108],"_links":{"self":[{"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/posts\/208"}],"collection":[{"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/comments?post=208"}],"version-history":[{"count":1,"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/posts\/208\/revisions"}],"predecessor-version":[{"id":209,"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/posts\/208\/revisions\/209"}],"wp:attachment":[{"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/media?parent=208"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/categories?post=208"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/tags?post=208"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}