Creating Virtual Disk

After open and attach, most common virtual disk operation will be create.

Here it is:

string fileName = @"D:\test.vhd";

long size = 128 * 1024 * 1024;

IntPtr handle = IntPtr.Zero;

var parameters = new CREATE_VIRTUAL_DISK_PARAMETERS();
parameters.Version = CREATE_VIRTUAL_DISK_VERSION.CREATE_VIRTUAL_DISK_VERSION_1;
parameters.Version1.BlockSizeInBytes = 0;
parameters.Version1.MaximumSize = size;
parameters.Version1.ParentPath = IntPtr.Zero;
parameters.Version1.SectorSizeInBytes = CREATE_VIRTUAL_DISK_PARAMETERS_DEFAULT_SECTOR_SIZE;
parameters.Version1.SourcePath = IntPtr.Zero;
parameters.Version1.UniqueId = Guid.Empty;

var storageType = new VIRTUAL_STORAGE_TYPE();
storageType.DeviceId = VIRTUAL_STORAGE_TYPE_DEVICE_VHD;
storageType.VendorId = VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT;

int res = CreateVirtualDisk(ref storageType, fileName, VIRTUAL_DISK_ACCESS_MASK.VIRTUAL_DISK_ACCESS_ALL, IntPtr.Zero, CREATE_VIRTUAL_DISK_FLAG.CREATE_VIRTUAL_DISK_FLAG_FULL_PHYSICAL_ALLOCATION, 0, ref parameters, IntPtr.Zero, ref handle);
if (res == ERROR_SUCCESS) {
} else {
    throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Native error {0}.", res));
}

// close handle to disk
CloseHandle(handle);

System.Windows.Forms.MessageBox.Show("Disk is created.");

Of course, in order for this to work, few P/Interop definitions are needed:

public const Int32 ERROR_SUCCESS = 0;

public const int CREATE_VIRTUAL_DISK_PARAMETERS_DEFAULT_SECTOR_SIZE = 0x200;
public const int VIRTUAL_STORAGE_TYPE_DEVICE_VHD = 2;
public static readonly Guid VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT = new Guid("EC984AEC-A0F9-47e9-901F-71415A66345B");

public enum CREATE_VIRTUAL_DISK_FLAG : int {
  CREATE_VIRTUAL_DISK_FLAG_NONE                     = 0x00000000,
  CREATE_VIRTUAL_DISK_FLAG_FULL_PHYSICAL_ALLOCATION = 0x00000001
}

public enum CREATE_VIRTUAL_DISK_VERSION : int {
  CREATE_VIRTUAL_DISK_VERSION_UNSPECIFIED = 0,
  CREATE_VIRTUAL_DISK_VERSION_1            = 1
}

public enum VIRTUAL_DISK_ACCESS_MASK : int {
  VIRTUAL_DISK_ACCESS_ATTACH_RO = 0x00010000,
  VIRTUAL_DISK_ACCESS_ATTACH_RW = 0x00020000,
  VIRTUAL_DISK_ACCESS_DETACH    = 0x00040000,
  VIRTUAL_DISK_ACCESS_GET_INFO  = 0x00080000,
  VIRTUAL_DISK_ACCESS_CREATE    = 0x00100000,
  VIRTUAL_DISK_ACCESS_METAOPS   = 0x00200000,
  VIRTUAL_DISK_ACCESS_READ      = 0x000d0000,
  VIRTUAL_DISK_ACCESS_ALL       = 0x003f0000,
  VIRTUAL_DISK_ACCESS_WRITABLE  = 0x00320000
}


[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct CREATE_VIRTUAL_DISK_PARAMETERS {
  public CREATE_VIRTUAL_DISK_VERSION Version;
  public CREATE_VIRTUAL_DISK_PARAMETERS_Version1 Version1;
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct CREATE_VIRTUAL_DISK_PARAMETERS_Version1 {
  public Guid UniqueId;
  public Int64 MaximumSize;
  public Int32 BlockSizeInBytes;
  public Int32 SectorSizeInBytes;
  public IntPtr ParentPath;
  public IntPtr SourcePath;
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct VIRTUAL_STORAGE_TYPE {
  public Int32 DeviceId;
  public Guid VendorId;
}


[DllImportAttribute("kernel32.dll", SetLastError = true)]
[return: MarshalAsAttribute(UnmanagedType.Bool)]
public static extern Boolean CloseHandle(IntPtr hObject);

[DllImport("virtdisk.dll", CharSet = CharSet.Unicode)]
public static extern Int32 CreateVirtualDisk(ref VIRTUAL_STORAGE_TYPE VirtualStorageType, String Path, VIRTUAL_DISK_ACCESS_MASK VirtualDiskAccessMask, IntPtr SecurityDescriptor, CREATE_VIRTUAL_DISK_FLAG Flags, int ProviderSpecificFlags, ref CREATE_VIRTUAL_DISK_PARAMETERS Parameters, IntPtr Overlapped, ref IntPtr Handle);

I think that this is as short as it gets without hard-coding values too much.

If you hate copy/paste, you can download this code sample. Notice that this code only creates virtual disk. If you want to take a look at more details, check full code sample.

P.S. Notice that this code will work with Windows 7 RC, but not with beta (API was changed in meantime).

P.P.S. If you get “Native error 1314.” exception, you didn’t run code as user with administrative rights. If you get “Native error 80.”, file you are trying to create is already there.