Displays which partitions are on which physical hard drives and shows partition starting offset and length.

Developed and tested under XP using a Borland C++ compiler.

Code is not provided for the private includes, but changes to make to code work are trival. References to werrtxt() and format() can be removed/replaced with alternate code.

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <conio.h>
#include <windows.h>
#include "bruce.i"    // Private functions, mostly string related
                      // Required by format()
#include "werrtxt.i"  // Print error text for GetLastError()
#include "format.i"   // Format numbers. 1234567 as 1,234,567
int main(int argc, char *argv[])
{
char data[256];
int i,j,k;
char Partition[26];
char Drive[26];
char DrivePart[26];
long double Starting_Offset[26];
long double Partition_Length[26];
int nparts=-1;
int maxdisk=0;
char DriveSpec[4]="?:\\";
char device[65];
char cnumber1[21];
char cnumber2[21];

HANDLE Device;
STORAGE_DEVICE_NUMBER sdn;
_PARTITION_INFORMATION_EX pi;
int piesz  = sizeof(PARTITION_INFORMATION_EX);
_DRIVE_LAYOUT_INFORMATION_EX *dlie;
int dliesz = sizeof(_DRIVE_LAYOUT_INFORMATION_EX);

bool GetDSN,GetPIB;
unsigned long bytes_returned;
BOOL SizeOK;
int numparts;

void *buffer; // Used to receive drive layout info
int bufsz;

// Determine what logical drives exist (partitions)
for (i='C'; i<='Z'; i++)
   {
   DriveSpec[0] = i;
   k = GetDriveType(DriveSpec);
   if (k == DRIVE_FIXED)
      {
      nparts++;
      Partition[nparts] = i;
      }
   }

printf("Partitions: %d\n",nparts+1);
for (i=0; i<=nparts; i++)
   {
   // -----------------------------------------------------------
   // All API information retrieval will be based on Drive Letter
   // -----------------------------------------------------------
   sprintf(device,"\\\\.\\%c:",Partition[i]);
   Device = CreateFile(device,                // drive 
            0,                                // no access to the drive
            FILE_SHARE_READ|FILE_SHARE_WRITE, // share mode
            NULL,                             // default security attributes
            OPEN_EXISTING,                    // disposition
            0,                                // file attributes
            NULL);                            // do not copy file attributes
   if (Device == INVALID_HANDLE_VALUE)
      {
      i = GetLastError();
      WErrTxt(i,data);
      printf("Error accessing drive %c:\nRC: x'%X'\nMessage: %s\n",Partition[i],data);
      return 2;
      }
   // -----------------------------------------------------------
   // Get the physical device this partition (drive letter) is on
   // -----------------------------------------------------------
   GetDSN = DeviceIoControl(Device,           // handle to device
            IOCTL_STORAGE_GET_DEVICE_NUMBER,  // dwIoControlCode
            NULL,                             // lpInBuffer
            0,                                // InBufferSize
            &sdn,                             // output buffer
            sizeof(STORAGE_DEVICE_NUMBER),    // size of output buffer
            &bytes_returned,                  // number of bytes returned
            NULL);                            // OVERLAPPED structure
   if (GetDSN)
       Drive[i] = (int) sdn.DeviceNumber;
   else
      {
      printf("Device number retrieval failed for %c:\n",Partition[i]);
      exit(0);
      }
   if (Drive[i] > maxdisk)
      maxdisk = Drive[i];
   // -----------------------------------------------------------
   // Get the partition number for the device (drive letter)
   // -----------------------------------------------------------
   GetPIB = DeviceIoControl(Device,           // handle to device
            IOCTL_DISK_GET_PARTITION_INFO_EX, // dwIoControlCode
            NULL,                             // lpInBuffer
            0,                                // InBufferSize
            &pi,                              // output buffer
            piesz,                            // size of output buffer
            &bytes_returned,                  // number of bytes returned
            NULL);                            // OVERLAPPED structure
   if (GetPIB)
      DrivePart[i] = pi.PartitionNumber;
   else
      {
      printf("Partition number retrieval failed for %c:\n",Partition[i]);
      exit(0);
      }
   // -----------------------------------------------------------
   // Get the extents for the device partition (drive letter)
   // -----------------------------------------------------------
   // Number of partitions on a drive varies, so don't know
   // how big a buffer we need right off the bat
   SizeOK = false;
   numparts = 1;
   buffer = (PARTITION_INFORMATION_EX *)
            malloc(sizeof(PARTITION_INFORMATION_EX)*4 *
            numparts + dliesz - piesz);
   // Up buffer size on each loop until success
   while(!SizeOK)
      {
      bufsz = sizeof(PARTITION_INFORMATION_EX)*4 * numparts + dliesz - piesz;
      bytes_returned = 0;
      SizeOK = DeviceIoControl(
               Device,                        // handle to device
               IOCTL_DISK_GET_DRIVE_LAYOUT_EX,// dwIoControlCode
               NULL,                          // lpInBuffer
               0,                             // nInBufferSize
               buffer,                        // output buffer
               bufsz,                         // size of output buffer
               &bytes_returned,               // number of bytes returned
               NULL);                         // OVERLAPPED structure
      if (!SizeOK)
         {
         k = GetLastError();
         if (k != 0x7A) // 7A is the buffer too small error code we expect
            {           // This something else, we need to check it out
            printf("Error retrieving disk layout data\n");
            WErrTxt(k,data);
            printf("RC: x'%X'\nMessage: %s\n",i,data);
            exit(0);
            }
         free(buffer); // Release the "too small" buffer
         numparts++;
         // Allocate new buffer based on updated partition "estimate"
         buffer = (PARTITION_INFORMATION_EX *)
                  malloc(sizeof(PARTITION_INFORMATION_EX)*
                  4 * numparts + dliesz - piesz);
         bufsz = sizeof(PARTITION_INFORMATION_EX)*4*numparts+dliesz-piesz;
         }
      }
   // Cast the void buffer to the Layout Structure
   // (Need Drive layout structure to point to data)
   dlie = (_DRIVE_LAYOUT_INFORMATION_EX *) buffer;
   for (j=0; j<dlie->PartitionCount; j++)
      {
      if (dlie->PartitionEntry[j].PartitionNumber == DrivePart[i])
         {
         // Need to conver LARGE_INTEGER fields to long double
         sprintf(data,"%I64d",dlie->PartitionEntry[j].PartitionLength);
         Partition_Length[i] = atof(data);
         sprintf(data,"%I64d",dlie->PartitionEntry[j].StartingOffset);
         Starting_Offset[i] = atof(data);
         break;
         }
      }
   free(buffer);        // Clean up allocated storage
   CloseHandle(Device); // Clean up acquired handle
   }
// Dump raw data to screen
for (j=0; j<=maxdisk; j++)
   {
   printf("\nDrive %d\n",j);
   printf("Dr  %17s %17s\n","Starting Offset","Partition Length");
   for (i=0; i<=nparts; i++)
      {
      if (Drive[i] == j)
         {
         // You'll need an alternative to format()
         printf("%c:  %17s %17s\n",
         Partition[i],
         format(Starting_Offset[i],cnumber1),
         format(Partition_Length[i],cnumber2));
         }
      }
   }
return 0;
}

Sample output
Partitions: 12

Drive 0
Dr    Starting Offset  Partition Length
C:             32,256    60,003,385,344
H:     60,003,449,856    60,003,385,344
P:    120,006,867,456   190,053,287,424
Q:    310,060,187,136   190,045,062,144

Drive 1
Dr    Starting Offset  Partition Length
D:             32,256   205,952,753,664
O:    205,952,818,176   114,117,502,464

Drive 2
Dr    Starting Offset  Partition Length
E:             32,256    80,048,392,704

Drive 3
Dr    Starting Offset  Partition Length
F:             32,256   160,039,240,704

Drive 4
Dr    Starting Offset  Partition Length
G:             32,256   160,039,240,704
I:    160,039,305,216    80,015,491,584
J:    240,054,829,056    80,015,491,584

Drive 5
Dr    Starting Offset  Partition Length
L:             32,256    81,956,657,664