Click here to Skip to main content
15,867,834 members
Articles / Programming Languages / XML
Tip/Trick

Determining all bootable partitions

Rate me:
Please Sign up or sign in to vote.
2.81/5 (6 votes)
28 Jun 2018CPOL2 min read 18.7K   319   3   17
Determining all bootable partitions using PInvoke

Image 1

Introduction

In this article, I will show how to determine boot partition of Windows OS with C# by using Win API (pinvoke).

Background

Windows OS has different types of partition on the disk. And there must be a system partition generally (C:\), other than this, there may be user partitions such as D: \, E:\. There may also be another type of partition such as Boot partition which is what constitutes the subject of our writing. Sometimes, developers want to identify boot partition in order not to damage the system because this partition is very important for boot operation of Windows OS.

Thanks to Richard, I realized boot indicator property is not valid on GPT disk. So I updated source code and article as compatible with GPT disk.

Using the Code

I used C# (Pinvoke). I have to define classic MS definitions which are structs, constants, etc. So I won't mention these definitions below.

The Native class contains definitions of structs, constants of Win API.

The NativeApi the class contains functions of Win API like,CreateFileDeviceIoControl  etc.

Firstly; We need to obtain handles of all hard drives which are mounted on the system. So we enumerate these drives. And then we can get partition list for all physical drives. Then we can enumerate all partitions.

This is full of body code:

C#
  public const uint MAX_NUMBER_OF_DRIVES = 64;

  for (uint i = 0; i < MAX_NUMBER_OF_DRIVES; i++)
  {
     // try to open the current physical drive
     string volume = string.Format("\\\\.\\PhysicalDrive{0}", i); 
     SafeFileHandle hndl = CreateFile(volume, Native.GENERIC_READ | Native.GENERIC_WRITE,
                                                Native.FILE_SHARE_READ | Native.FILE_SHARE_WRITE,
                                                IntPtr.Zero,
                                                Native.OPEN_EXISTING,
                                                Native.FILE_ATTRIBUTE_READONLY,
                                                IntPtr.Zero);
     //We have got handle now.

     //Some necessary variables definitions
     IntPtr driveLayoutPtr = IntPtr.Zero;
     int DRIVE_LAYOUT_BUFFER_SIZE = 1024;
     int error;
     uint dummy = 0;
                
     do
     {
       error = 0;
       driveLayoutPtr = Marshal.AllocHGlobal(DRIVE_LAYOUT_BUFFER_SIZE);
       if (DeviceIoControl
          (hndl, Native.IOCTL_DISK_GET_DRIVE_LAYOUT_EX, IntPtr.Zero, 0, driveLayoutPtr, 
          (uint)DRIVE_LAYOUT_BUFFER_SIZE, ref dummy, IntPtr.Zero))
          {
            // I/O-control has been invoked successfully, 
            //convert to DRIVE_LAYOUT_INFORMATION_EX
             DRIVE_LAYOUT_INFORMATION_EX driveLayout = (DRIVE_LAYOUT_INFORMATION_EX)
             Marshal.PtrToStructure(driveLayoutPtr, typeof(DRIVE_LAYOUT_INFORMATION_EX));
             //Now i have got partition
             for (uint p = 0; p < driveLayout.PartitionCount; p++)
             {
                //Enumerate partition by using pointer arithmetic
                IntPtr ptr = new IntPtr(driveLayoutPtr.ToInt64() + 
                Marshal.OffsetOf(typeof(DRIVE_LAYOUT_INFORMATION_EX), "PartitionEntry").ToInt64()
                + (p * Marshal.SizeOf(typeof(PARTITION_INFORMATION_EX))));

                PARTITION_INFORMATION_EX partInfo = (PARTITION_INFORMATION_EX)
                Marshal.PtrToStructure(ptr, typeof(PARTITION_INFORMATION_EX));
                //Check partition is recognized or not
               if (partInfo.PartitionStyle != PARTITION_STYLE.PARTITION_STYLE_GPT)
               {
                 if ((partInfo.PartitionStyle != PARTITION_STYLE.PARTITION_STYLE_MBR) || 
                     (partInfo.Mbr.RecognizedPartition))
                 {
                   if (partInfo.Mbr.BootIndicator == true)
                   {
                    Console.WriteLine("Drive No: " + i + " Partition Number :" + 
                                       partInfo.PartitionNumber + " is boot partition");

                   }

                 }
               }
               else if (partInfo.PartitionStyle == PARTITION_STYLE.PARTITION_STYLE_GPT) {
                 //e3c9e316-0b5c-4db8-817d-f92df00215ae guid is defined from MS here:
                 //https://msdn.microsoft.com/en-us/library/windows/desktop/aa365449(v=vs.85).aspx
                 if (partInfo.Gpt.PartitionType== new Guid("e3c9e316-0b5c-4db8-817d-f92df00215ae"))
                 {
                 Console.WriteLine("Drive No: " + i + " Partition Number :" 
                                  + partInfo.PartitionNumber + " is boot partition");


                 }
              }
             }
            }
       else
       {
          error = Marshal.GetLastWin32Error();
          DRIVE_LAYOUT_BUFFER_SIZE *= 2;                    
        }
       Marshal.FreeHGlobal(driveLayoutPtr);
       driveLayoutPtr = IntPtr.Zero;
  } while (error == Native.ERROR_INSUFFICIENT_BUFFER);
}

As seen above, we get all partitions and check each one is BootIndicator or not.

The important thing is at first, filling DRIVE_LAYOUT_INFORMATION_EX structure by using the DeviceIoControl function. And then there is pointer arithmetic to extract buffer. Finally, We need to convert byte buffer to the PARTITION_INFORMATION_EX structure. That's all!

Don't forget that boot partition doesn't have to be separated on all Windows installed machines. Consider that boot OS files may be on OS installed partition which is generally " Local Disk (C:) ".

Finally, if you want to test sample application, the application requires administrator credentials to run correctly.

 

Points of Interest

I wrote this article for developers which are interested in Win API programming. And I think low-level programming is very hard and interesting. So I like learning new things when I develop a program. I think if you are interested in learning fundamentals of something, then this topic will help you to identify boot partition programmatically. I hope you enjoyed reading this article.

This article was originally posted at https://github.com/codeparksoftware/BootPartition

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) codepark software
Turkey Turkey
I m interested in C# ,Java,Delphi programming language.I developed many types program which are generally enterprise solution.I m also interested in security ,forensic,system software development,encryption,Windows services,network programming .I have a OOP and Desing Patterns book writing work.

Comments and Discussions

 
QuestionProgram Does not return to a command prompt Pin
Member 1579876019-Dec-22 5:19
Member 1579876019-Dec-22 5:19 
BugWill Fail on system with multiple bootable drives Pin
Randor 23-Jun-18 22:27
professional Randor 23-Jun-18 22:27 
GeneralRe: Will Fail on system with multiple bootable drives Pin
hasan bozkurt23-Jun-18 22:53
hasan bozkurt23-Jun-18 22:53 
GeneralRe: Will Fail on system with multiple bootable drives Pin
Randor 23-Jun-18 23:09
professional Randor 23-Jun-18 23:09 
GeneralRe: Will Fail on system with multiple bootable drives Pin
hasan bozkurt24-Jun-18 10:56
hasan bozkurt24-Jun-18 10:56 
GeneralRe: Will Fail on system with multiple bootable drives Pin
Randor 24-Jun-18 14:12
professional Randor 24-Jun-18 14:12 
GeneralRe: Will Fail on system with multiple bootable drives Pin
hasan bozkurt25-Jun-18 0:17
hasan bozkurt25-Jun-18 0:17 
GeneralRe: Will Fail on system with multiple bootable drives Pin
Randor 25-Jun-18 4:15
professional Randor 25-Jun-18 4:15 
GeneralRe: Will Fail on system with multiple bootable drives Pin
hasan bozkurt25-Jun-18 23:00
hasan bozkurt25-Jun-18 23:00 
GeneralRe: Will Fail on system with multiple bootable drives Pin
Randor 26-Jun-18 5:17
professional Randor 26-Jun-18 5:17 
GeneralRe: Will Fail on system with multiple bootable drives Pin
hasan bozkurt26-Jun-18 8:03
hasan bozkurt26-Jun-18 8:03 
QuestionSomething wrong shirley ... Pin
Richard MacCutchan23-Jun-18 7:03
mveRichard MacCutchan23-Jun-18 7:03 
AnswerRe: Something wrong shirley ... Pin
hasan bozkurt23-Jun-18 9:04
hasan bozkurt23-Jun-18 9:04 
Hello Richard,
Thanks for your interest and answer. I developed this program in Win7 and it works correctly for me. There are two mounted HDD on my machine. It works fine.
I suppose you have a different OS and I don't have clue for this mistake. Can you share additional info about your system with us to help you?
GeneralRe: Something wrong shirley ... Pin
Richard MacCutchan23-Jun-18 9:47
mveRichard MacCutchan23-Jun-18 9:47 
GeneralRe: Something wrong shirley ... Pin
hasan bozkurt23-Jun-18 10:35
hasan bozkurt23-Jun-18 10:35 
GeneralRe: Something wrong shirley ... Pin
hasan bozkurt23-Jun-18 12:08
hasan bozkurt23-Jun-18 12:08 
GeneralRe: Something wrong shirley ... Pin
Richard MacCutchan23-Jun-18 21:29
mveRichard MacCutchan23-Jun-18 21:29 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.