Get Partitions from a DISK with DeviceIoControl IOCTL_DISK_GET_DRIVE_LAYOUT_EX

I wrote once Clarion code, to get the DRIVE LAYOUT , Partitions in particular of a Harddisk.

The output bytes following the structure as how the MSDN describes it, is not fully correct so I used a Offset# (you can ignore the increasing P#) as each Partition block does have the exact size)

It can see what type of Partition type (MBR of GPT)

up here the code:

DeviceIoControl_IOCTL_DISK_GET_DRIVE_LAYOUT_EX ROUTINE

IOReturn  = DeviceIoControl(LDeviceHandle, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, 0, 0, Address(LBUFFER16K), Size(LBUFFER16K), 0, Address(IOverlapped[IOverlappedIndex]))

!https://docs.microsoft.com/en-us/windows/win32/api/winioctl/ns-winioctl-drive_layout_information_ex

PROCESS_DATA_IOCTL_DISK_GET_DRIVE_LAYOUT_EX ROUTINE

If OverlappedBytesReturned > 0
    MaxQLXBytes = OverlappedBytesReturned
    Buffer64K = LBUFFER16K
    Do SaveQLXBytes
    
    Clear(QLDevicePropExt)
    QLDevicePropExtSeed             = QLDevicePropExtSeed + 1
    QLDevPropExt:Id                 = QLDevicePropExtSeed
    QLDevPropExt:MachineId          = ThisMachineId
    QLDevPropExt:WinWorker          = LWinWorkerIndex
    QLDevPropExt:DeviceId           = LQDeviceId
    
    QLDevPropExt:MessageId          = GLHDWorkerMes.MessageId
    QLDevPropExt:FunctionCall       = GetHDInfoPhase
    QLDevPropExt:OK                 = 0
    QLDevPropExt:ERROR              = 0
    QLDevPropExt:LASTERRORCODE      = 0
    QLDevPropExt:DURATION           = Clock() - StartTimeDeviceIoControl                             
    
    QLDevPropExt:TagNameA           = 'IOCTL_DISK_GET_DRIVE_LAYOUT_EX'
    QLDevPropExt:TagNameLen         = Len(Clip(QLDevPropExt:TagNameA)) * 2
    QLDevPropExt:NameA              = 'OverlappedBytesReturned'
    QLDevPropExt:NameLen            = Len(Clip(QLDevPropExt:NameA)) * 2
    QLDevPropExt:DataType           = 1
    QLDevPropExt:DataTypeString     = 'bool'
    QLDevPropExt:ValueA             = OverlappedBytesReturned
    QLDevPropExt:ValueLen           = 1
    Add(QLDevicePropExt)

!#define GPT_BASIC_DATA_ATTRIBUTE_NO_DRIVE_LETTER (0x8000000000000000)
!#define GPT_BASIC_DATA_ATTRIBUTE_HIDDEN (0x4000000000000000)
!#define GPT_BASIC_DATA_ATTRIBUTE_SHADOW_COPY (0x2000000000000000)
!#define GPT_BASIC_DATA_ATTRIBUTE_READ_ONLY (0x1000000000000000)
!#define GPT_BASIC_DATA_ATTRIBUTE_OFFLINE (0x0800000000000000)
!#define GPT_BASIC_DATA_ATTRIBUTE_DAX (0x0400000000000000)
!#define GPT_BASIC_DATA_ATTRIBUTE_SERVICE (0x0200000000000000)

    Clear(GrpDriveLayoutInformationEx)
    GrpDriLayInfEx:PartitionStyle               = GetU32(LBUFFER16K[1:4])                
    GrpDriLayInfEx:PartitionCount               = GetU32(LBUFFER16K[5:8])  
    
    
    
    P# = 0
    Case GrpDriLayInfEx:PartitionStyle
    Of 0
        GrpDriLayInfEx:PartitionStyleA          = 'MBR'
        
        GrpDriLayInfEx:MBR_Signature            = GetU32(LBUFFER16K[9:12]) 
        GrpDriLayInfEx:MBR_SignatureHex         = Upper(st.ByteToHex(Val(LBUFFER16K[12])) & st.ByteToHex(Val(LBUFFER16K[11])) & st.ByteToHex(Val(LBUFFER16K[10])) & st.ByteToHex(Val(LBUFFER16K[9])))
        
        GrpDriLayInfEx:MBR_Checksum             = GetU32(LBUFFER16K[13:16]) 
        GrpDriLayInfEx:MBR_ChecksumHex          = Upper(st.ByteToHex(Val(LBUFFER16K[16])) & st.ByteToHex(Val(LBUFFER16K[15])) & st.ByteToHex(Val(LBUFFER16K[14])) & st.ByteToHex(Val(LBUFFER16K[13])))
        !P# = 17
        P# = 53
    Of 1
        GrpDriLayInfEx:PartitionStyleA          = 'GPT'
        GrpDriLayInfEx:GPT_GuidDiskId           = ConvertToGuidRaw(LBUFFER16K[9 : 24])
        GrpDriLayInfEx:GPT_StartingUsableOffset = GetU64(LBUFFER16K[25 : 33])
        GrpDriLayInfEx:GPT_UsableLength         = GetU64(LBUFFER16K[34 : 41])
        GrpDriLayInfEx:GPT_MaxPartitionCount    = GetU32(LBUFFER16K[42 : 45])
        P# = 49
    Of 2
        GrpDriLayInfEx:PartitionStyleA          = 'OTHER'
    End
    
    !Offset# = 49
    Offset# = P#
    
    
    PartitionId = 0
    Loop !1 Times
        !BREAK
        
        
        PartitionId = PartitionId + 1
        If PartitionId > GrpDriLayInfEx:PartitionCount
            BREAK
        End
        P# = Offset# + (PartitionId * 144) - 144
        If P# > Size(LBUFFER16K) - 200
            BREAK
        End
        Case Clip(GrpDriLayInfEx:PartitionStyleA)
        Of 'MBR'
            QLMbrPrtInfEx:PartitionStyle        = Val(LBUFFER16K[P#]) !GetU32(LBUFFER16K[P# : P# + 3])   
            Case QLMbrPrtInfEx:PartitionStyle
            Of 0
                QLMbrPrtInfEx:PartitionStyleStringA = 'MBR'
            Of 1
                QLMbrPrtInfEx:PartitionStyleStringA = 'GPT'
            Of 2
                QLMbrPrtInfEx:PartitionStyleStringA = 'RAW'
            END
            P# = P# + 4
            
            QLMbrPrtInfEx:StartingOffset        = GetU64(LBUFFER16K[P# : P# + 7])
            QLMbrPrtInfEx:StartingOffset        = QLMbrPrtInfEx:StartingOffset / 512
            P# = P# + 8
            
            QLMbrPrtInfEx:PartitionLength       = GetU64(LBUFFER16K[P# : P# + 7])
            QLMbrPrtInfEx:PartitionLength       = QLMbrPrtInfEx:PartitionLength / 512
            P# = P# + 8
            
            QLMbrPrtInfEx:PartitionNumber       = GetU32(LBUFFER16K[P# : P# + 3])
            P# = P# + 4
            
            QLMbrPrtInfEx:RewritePartition      = Val(LBUFFER16K[P#])
            P# = P# + 1
            QLMbrPrtInfEx:IsServicePartition    = Val(LBUFFER16K[P#])
            P# = P# + 1

            ! specific MBR
            QLMbrPrtInfEx:PartitionType         = Val(LBUFFER16K[P#])
            P# = P# + 4
            QLMbrPrtInfEx:BootIndicator         = Val(LBUFFER16K[P#])
            P# = P# + 1
            QLMbrPrtInfEx:RecognizedPartition   = Val(LBUFFER16K[P#])
            P# = P# + 1
            QLMbrPrtInfEx:HiddenSectors         = GetU32(LBUFFER16K[P# : P# + 3])
            P# = P# + 4
            QLMbrPrtInfEx:HiddenSectors         = GetU32(LBUFFER16K[P# : P# + 3])
            P# = P# + 4
            QLMbrPrtInfEx:GuidPartitionId       = ConvertToGuid(LBUFFER16K[P# : P# + 15])
            P# = P# + 16
            
            Add(QLMbrPartitionInfEx)
        Of 'GPT'
            !QLGptPrtInfEx:YourId = P#
            Offset# = 49
            P# = Offset# + (PartitionId * 144) - 144
            
            QLGptPrtInfEx:PartitionStyle        = Val(LBUFFER16K[P#])  
            Case QLGptPrtInfEx:PartitionStyle
            Of 0
                QLGptPrtInfEx:PartitionStyleStringA = 'MBR'
            Of 1
                QLGptPrtInfEx:PartitionStyleStringA = 'GPT'
            Of 2
                QLGptPrtInfEx:PartitionStyleStringA = 'RAW'
            END
            
            Offset# = 57
            P# = Offset# + (PartitionId * 144) - 144
            QLGptPrtInfEx:ID = P#
            QLGptPrtInfEx:StartingOffset        = GETU64(LBUFFER16K[P# : P# + 7])
            QLGptPrtInfEx:StartingOffset        = QLGptPrtInfEx:StartingOffset / 512
            P# = P# + 8
            
            
            Offset# = 65
            P# = Offset# + (PartitionId * 144) - 144
            QLGptPrtInfEx:YourId = P#
            QLGptPrtInfEx:PartitionLength       = GetU64(LBUFFER16K[P# : P# + 7])
            QLGptPrtInfEx:PartitionLength       = QLGptPrtInfEx:PartitionLength / 512
            P# = P# + 8

            
            Offset# = 73
            P# = Offset# + (PartitionId * 144) - 144
            QLGptPrtInfEx:PartitionNumber       = GetU32(LBUFFER16K[P# : P# + 3])
            P# = P# + 4
            
            Offset# = 77
            P# = Offset# + (PartitionId * 144) - 144
            QLGptPrtInfEx:RewritePartition      = Val(LBUFFER16K[P#])
            P# = P# + 1
            
            Offset# = 78
            P# = Offset# + (PartitionId * 144) - 144
            QLGptPrtInfEx:IsServicePartition    = Val(LBUFFER16K[P#])
            P# = P# + 1                
            

            Offset# = 81
            P# = Offset# + (PartitionId * 144) - 144
            QLGptPrtInfEx:GuidPartitionTypeA    = Lower(ConvertToGuid(LBUFFER16K[P# : P# + 15]))
            Case QLGptPrtInfEx:GuidPartitionTypeA
            Of PARTITION_BASIC_DATA_GUID       !EQUATE('ebd0a0a2-b9e5-4433-87c0-68b6b72699c7')
                QLGptPrtInfEx:GuidPartitionTypeName = 'Basic Data'
            Of PARTITION_ENTRY_UNUSED_GUID     !EQUATE('00000000-0000-0000-0000-000000000000')
                QLGptPrtInfEx:GuidPartitionTypeName = 'Unused'
            Of PARTITION_SYSTEM_GUID           !EQUATE('c12a7328-f81f-11d2-ba4b-00a0c93ec93b')
                QLGptPrtInfEx:GuidPartitionTypeName = 'System'
            Of PARTITION_MSFT_RESERVED_GUID    !EQUATE('e3c9e316-0b5c-4db8-817d-f92df00215ae')
                QLGptPrtInfEx:GuidPartitionTypeName = 'Reserved'
            Of PARTITION_LDM_METADATA_GUID     !EQUATE('5808c8aa-7e8f-42e0-85d2-e1e90434cfb3')
                QLGptPrtInfEx:GuidPartitionTypeName = 'LDM Metadata'
            Of PARTITION_LDM_DATA_GUID         !EQUATE('af9b60a0-1431-4f62-bc68-3311714a69ad')
                QLGptPrtInfEx:GuidPartitionTypeName = 'LDM Data'
            Of PARTITION_MSFT_RECOVERY_GUID    !EQUATE('de94bba4-06d1-4d40-a16a-bfd50179d6ac')
                QLGptPrtInfEx:GuidPartitionTypeName = 'MSFT Recovery'
            Of PARTITION_STORAGE_SPACES        !EQUATE('e75caf8f-f680-4cee-afa3-b001e56efc2d')                
                QLGptPrtInfEx:GuidPartitionTypeName = 'Storage Spaces'
            Else
                QLGptPrtInfEx:GuidPartitionTypeName = 'other'
            End
            P# = P# + 16
            
            Offset# = 97
            P# = Offset# + (PartitionId * 144) - 144
            QLGptPrtInfEx:GuidPartitionId       = Lower(ConvertToGuidRaw(LBUFFER16K[P# : P# + 15]))
            P# = P# + 16                

            
            Offset# = 113
            P# = Offset# + (PartitionId * 144) - 144
            QLGptPrtInfEx:Attributes            = GetU64(LBUFFER16K[P# : P# + 7])
            P# = P# + 8
            
            Offset# = 121
            P# = Offset# + (PartitionId * 144) - 144
            QLGptPrtInfEx:Name                  = LBUFFER16K[P# : P# + 72]
            QLGptPrtInfEx:NameA                 = ConvertToASCII(QLGptPrtInfEx:Name, 72)

            
            Add(QLGptPartitionInfEx)
        End

    End
End