How to Initialize Disk

When new EMPTY disk is added to Windows first thing that needs to be done is initialization. Only after this step Windows will recognize disk as their own and allow you to create partitions.

Part of (bigger) script was automatic disk initialization. Surfing Internet yielded just few results for this particular problem. Most of them were using DISKPART and this was not acceptable. I needed something in Win32 API.

Theory is simple enough. Single function that does it all is DeviceIoControl. Unfortunately this function is ridiculously overloaded. Little bit of investigation will bring us to IOCTL_DISK_CREATE_DISK control code which does disk initialization. Even better - almost all parameters can be ignored or set to default.

Only parameter that we must understand is CREATE_DISK structure so it is only appropriate to have it use unions. As you might know, there is no meaningful support for unions in C#. There is a way around it with FieldOffset(0) but it does not look nice.

Rest of code is fairly straightforward. To call it just use DiskIO.InitializeDisk("\\.\PHYSICALDRIVE4") (substitute number for whichever drive you wish to initialize).

Full code follows:

internal static class DiskIO {

public static void InitializeDisk(string path) {
var signature = new byte[4];
RandomNumberGenerator.Create().GetBytes(signature); //lazy way to generate "unique" signature

using (SafeFileHandle handle = NativeMethods.CreateFile(path, NativeMethods.GENERIC_READ | NativeMethods.GENERIC_WRITE, 0, IntPtr.Zero, NativeMethods.OPEN_EXISTING, 0, IntPtr.Zero)) {
if (handle.IsInvalid) { throw new Win32Exception(); }

var cd = new NativeMethods.CREATE_DISK();
cd.PartitionStyle = NativeMethods.PARTITION_STYLE.PARTITION_STYLE_MBR;
cd.MbrGpt.Mbr.Signature = BitConverter.ToInt32(signature, 0);
Int32 bytesOut = 0;
if (NativeMethods.DeviceIoControl(handle, NativeMethods.IOCTL_DISK_CREATE_DISK, ref cd, Marshal.SizeOf(cd), IntPtr.Zero, 0, ref bytesOut, IntPtr.Zero) == false) { throw new Win32Exception(); }
}
}


private static class NativeMethods {

public const int GENERIC_READ = -2147483648;
public const int GENERIC_WRITE = 1073741824;
public const int OPEN_EXISTING = 3;

public const int IOCTL_DISK_CREATE_DISK = 0x7C058;


public enum PARTITION_STYLE {
PARTITION_STYLE_MBR = 0,
PARTITION_STYLE_GPT = 1,
PARTITION_STYLE_RAW = 2,
}


[StructLayoutAttribute(LayoutKind.Sequential)]
public struct CREATE_DISK {
public PARTITION_STYLE PartitionStyle;
public CREATE_DISK_UNION_MBR_GPT MbrGpt;
}

[StructLayoutAttribute(LayoutKind.Explicit)]
public struct CREATE_DISK_UNION_MBR_GPT {
[FieldOffset(0)]
public CREATE_DISK_MBR Mbr;
[FieldOffset(0)]
public CREATE_DISK_GPT Gpt;
}


[StructLayoutAttribute(LayoutKind.Sequential)]
public struct CREATE_DISK_MBR {
public Int32 Signature;
}

[StructLayoutAttribute(LayoutKind.Sequential)]
public struct CREATE_DISK_GPT {
public Guid DiskId;
public Int32 MaxPartitionCount;
}


[DllImportAttribute("kernel32.dll", EntryPoint = "CreateFileW", SetLastError = true)]
public static extern SafeFileHandle CreateFile([MarshalAsAttribute(UnmanagedType.LPWStr)] string lpFileName, Int32 dwDesiredAccess, Int32 dwShareMode, IntPtr lpSecurityAttributes, Int32 dwCreationDisposition, Int32 dwFlagsAndAttributes, IntPtr hTemplateFile);

[DllImportAttribute("kernel32.dll", EntryPoint = "DeviceIoControl", SetLastError = true)]
[return: MarshalAsAttribute(UnmanagedType.Bool)]
public static extern Boolean DeviceIoControl(SafeFileHandle hDevice, Int32 dwIoControlCode, ref CREATE_DISK lpInBuffer, int nInBufferSize, IntPtr lpOutBuffer, Int32 nOutBufferSize, ref Int32 lpBytesReturned, IntPtr lpOverlapped);

}

}

Leave a Reply

Your email address will not be published. Required fields are marked *