Programming in C#, Java, and god knows what not

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.

Visual Studio and WPF

Illustration

Visual Studio 2010 really shines with its new WPF interface. Side effect of this is relying little bit more on your graphics card. If graphics driver has a bug, you have a problem.

It seems that nobody at Microsoft tested their Visual Studio 2010 beta 1 with Intel’s GE45 integrated graphics. At least once per hour I get “Display driver stopped responding and had recovered” balloon. While this is not end of world, it is pretty annoying.

While this is probably driver problem, I cannot help but to put some blame on Microsoft since only application that ever caused this bug was Visual Studio 2010. Of course I need to blame myself a little also, since I am the one using both Windows 7 and Visual Studio 2010 in their beta stage.

[2009-07-22: New Intel graphics driver is issued over Windows Update with June 2009 markings. It seems that this driver solves problem. I used it for few hours straight without any issues. I do hope it stays that way.]

*WORD

In times of 8-bit systems byte (octet) was used to denote processors data size. When 16-bit computers appeared, WORD was used for sizes same as size of processor’s data bus. At those times, one WORD was equal to two bytes.

Once 32-bit computing came around, choice needed to be made. Whether to re-use WORD (but to alter it’s 16-bit era meaning) or to make new unit. DWORD (double WORD) was born to signify this new bus width. On 64-bit computers, natural choice was QWORD (quadruple WORD).

Is OWORD (octal WORD) next?

Why ULONG Is 32-Bit Even on 64-Bit Windows

When you prepare C#'s DllImport functions, remember that if you see ULONG, you need to convert it as Int32 (more precise would be UInt32). Although one would assume that ULONG would be 64-bit on 64-bit systems, it is actually four bytes on both 32-bit and 64-bit systems.

Reason this happens is Microsoft’s decision to use LLP64 data model for Windows API. This was done in order to ease switch to 64-bits for C++ programs. All API calls that were done on 32-bit systems that had ULONG in it, will work same even in 64-bit world. Easiest change is one that requires no action.

If you really want something with 64 bits, use ULONGLONG (or LONGLONG). This one is eight bytes in both 32-bit and 64-bit environment.

Beware if you see pointer to ULONG. Even if ULONG is four bytes on 64-bit platform, pointer to it is eight bytes. As matter of fact, all pointers are eight bytes.

Visual Studio 2010 Beta 1

I played a little with this thing and I can only say that I cannot believe that this is WPF application. I wanted to check how mobile development looks like but I could not find it in this version.

I really wanted to check whether Cellular Emulator finally works under 64-bit Windows but it seems that I will need to wait until next version.

Which Brace Style to Use

Among C-ish programmers, there is often dispute which brace style to use. K&R style (named after authors of The C Programming Language)

void Main() {
  Console.WriteLine("Hello World!");
}

was very popular once, but Allman style

void Main()
{
  Console.WriteLine("Hello World!");
}

is what seems to be popular now. Basically only difference is where to put starting brace. Whether it stands behind control statement or it stands on dedicated line. And that is something that people cannot decide for quite a while now. Both of them have their advantages that I will not discuss here (there is pretty good article on Wikipedia).

I am currently using K&R style. Here I will try to make two points why everyone should switch to Allman.

Visual Studio defaults

Default brace style for C# is Allman. If you need to modify code written by others, that code will rarely use K&R. While Visual Studio and C# do give you great options of reformatting code, I consider doing that just being rude.

I was known to change formatting of code in other people files and it took me a while to understand how unreadable whole project becomes when half of files use one style and half another. Now, if project has established style, I will continue adding stuff in same style.

Readability

If you are used to code in one style, you are better at scanning code in that style. If you get Allman code, it helps to be used to Allman to read it faster. It does not hurt too much if your code preference is different, but there is some speed advantage.

Conclusion

I can see that I should code in Allman all the time. I know it would be beneficial. But I cannot force myself to do it. Although all reasoning says that Allman is more readable, it seems that my mind is just not used to it. It just likes to find them by indentation rather than by matching braces.

Maybe it is because I have history in VB which looks quite like K&R in indentation style, maybe it is because I never gave Allman more than a week to get used to, maybe it is just because I like to be different.

Against of all reasoning - I am sticking with K&R for now.

Open and Attach

This will be just short example of using Windows 7 Virtual disk API functions. Although I also gave full example, quite a few people asked me for shorter example which will just illustrate operations that will be used most often - open and attach.

Here it is:

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

IntPtr handle = IntPtr.Zero;


// open disk handle
var openParameters = new OPEN_VIRTUAL_DISK_PARAMETERS();
openParameters.Version = OPEN_VIRTUAL_DISK_VERSION.OPEN_VIRTUAL_DISK_VERSION_1;
openParameters.Version1.RWDepth = OPEN_VIRTUAL_DISK_RW_DEPTH_DEFAULT;

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

int openResult = OpenVirtualDisk(ref openStorageType, fileName, VIRTUAL_DISK_ACCESS_MASK.VIRTUAL_DISK_ACCESS_ALL, OPEN_VIRTUAL_DISK_FLAG.OPEN_VIRTUAL_DISK_FLAG_NONE, ref openParameters, ref handle);
if (openResult != ERROR_SUCCESS) {
    throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Native error {0}.", openResult));
}


// attach disk - permanently
var attachParameters = new ATTACH_VIRTUAL_DISK_PARAMETERS();
attachParameters.Version = ATTACH_VIRTUAL_DISK_VERSION.ATTACH_VIRTUAL_DISK_VERSION_1;
int attachResult = AttachVirtualDisk(handle, IntPtr.Zero, ATTACH_VIRTUAL_DISK_FLAG.ATTACH_VIRTUAL_DISK_FLAG_PERMANENT_LIFETIME, 0, ref attachParameters, IntPtr.Zero);
if (attachResult != ERROR_SUCCESS) {
    throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Native error {0}.", attachResult));
}


// close handle to disk
CloseHandle(handle);

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

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

public const Int32 ERROR_SUCCESS = 0;

public const int OPEN_VIRTUAL_DISK_RW_DEPTH_DEFAULT = 1;

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 ATTACH_VIRTUAL_DISK_FLAG : int {
  ATTACH_VIRTUAL_DISK_FLAG_NONE               = 0x00000000,
  ATTACH_VIRTUAL_DISK_FLAG_READ_ONLY          = 0x00000001,
  ATTACH_VIRTUAL_DISK_FLAG_NO_DRIVE_LETTER    = 0x00000002,
  ATTACH_VIRTUAL_DISK_FLAG_PERMANENT_LIFETIME = 0x00000004,
  ATTACH_VIRTUAL_DISK_FLAG_NO_LOCAL_HOST      = 0x00000008
}

public enum ATTACH_VIRTUAL_DISK_VERSION : int {
  ATTACH_VIRTUAL_DISK_VERSION_UNSPECIFIED = 0,
  ATTACH_VIRTUAL_DISK_VERSION_1 = 1
}

public enum OPEN_VIRTUAL_DISK_FLAG : int {
  OPEN_VIRTUAL_DISK_FLAG_NONE       = 0x00000000,
  OPEN_VIRTUAL_DISK_FLAG_NO_PARENTS = 0x00000001,
  OPEN_VIRTUAL_DISK_FLAG_BLANK_FILE = 0x00000002,
  OPEN_VIRTUAL_DISK_FLAG_BOOT_DRIVE = 0x00000004
}

public enum OPEN_VIRTUAL_DISK_VERSION : int {
  OPEN_VIRTUAL_DISK_VERSION_1 = 1
}


[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct ATTACH_VIRTUAL_DISK_PARAMETERS {
  public ATTACH_VIRTUAL_DISK_VERSION Version;
  public ATTACH_VIRTUAL_DISK_PARAMETERS_Version1 Version1;
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
ublic struct ATTACH_VIRTUAL_DISK_PARAMETERS_Version1 {
  public Int32 Reserved;
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct OPEN_VIRTUAL_DISK_PARAMETERS {
  public OPEN_VIRTUAL_DISK_VERSION Version;
  public OPEN_VIRTUAL_DISK_PARAMETERS_Version1 Version1;
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct OPEN_VIRTUAL_DISK_PARAMETERS_Version1 {
  public Int32 RWDepth;
}

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 VIRTUAL_STORAGE_TYPE {
  public Int32 DeviceId;
  public Guid VendorId;
}

[DllImport("virtdisk.dll", CharSet = CharSet.Unicode)]
public static extern Int32 AttachVirtualDisk(IntPtr VirtualDiskHandle, IntPtr SecurityDescriptor, ATTACH_VIRTUAL_DISK_FLAG Flags, Int32 ProviderSpecificFlags, ref ATTACH_VIRTUAL_DISK_PARAMETERS Parameters, IntPtr Overlapped);

[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 OpenVirtualDisk(ref VIRTUAL_STORAGE_TYPE VirtualStorageType, String Path, VIRTUAL_DISK_ACCESS_MASK VirtualDiskAccessMask, OPEN_VIRTUAL_DISK_FLAG Flags, ref OPEN_VIRTUAL_DISK_PARAMETERS Parameters, 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 opens virtual disk. If you want to create it or 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 32.”, virtual disk is already attached. Just go to Disk Management console and select Detach VHD on right-click menu.

Virtual Disk API After RC

I already wrote about Virtual disk API support in Windows 7. All that was based on beta so, now with Windows 7 RC in wild, some corrections are in order.

Microsoft decided to replace word surface with attach. While plenty of those changes were done in beta also (e.g. DISKPART), renaming of API functions was timed for release candidate. Since this change invalidates my previous code examples on how to work with virtual disks, here is new example that works with RC (but doesn’t work with beta).

Usual practice for release candidate is to be code-complete - hopefully no further API changes will be done before final version.

P.S. This code is work in progress, in no way it is production quality.

[2009-05-03: There was bug with one parameter in code. On beta, that bug went unnoticed, but on release candidate it causes open operation to fail with native error 87. I updated source code so all further downloads will point to correct files.]

[2009-06-12: There was change in enumerations from beta to RC that I missed. Side effect of it was inability to permanently attach virtual disk. This is fixed now (to make it more embarrassing, I used correct code in Open and attach sample but somehow I missed to notice the difference).]

AutoUpgradeEnabled

My program was failing with MissingMethodException (Method not found: ‘Void System.Windows.Forms.FileDialog.set_AutoUpgradeEnabled(Boolean)’). This happened only on Windows XP and not all of them.

Culprit was obvious. I used OpenFileDialog and I decided to set AutoUpgradeEnabled property. Only problem was that this property was introduced with .NET Framework 2.0 SP1. Notice this service pack part - that property does not exist if you have version without it.

Solution is easy if you are trying setting this property to true - that is default value anyhow. If you want to set it to false, just use reflection:

var property = typeof(FileDialog).GetProperty("AutoUpgradeEnabled");
if (property != null) {
  property.SetValue(openFileDialog1, false, null);
}

Notice that this property is shared among other controls inheriting from FileDialog (e.g. SaveFileDialog) so same thing applies to them also.

How Union Works

Most of Win32 functions are user friendly. Not as user friendly as .NET framework, but once you see specification, everything is clear. There is no problem translating it to P/Interop call.

But there is one issue that may be problematic - unions. They are used in C++ programs in order to force multiple variables to use same memory space. We will use INPUT structure as example here:

typedef struct tagINPUT {
  DWORD type;
  union {
    MOUSEINPUT mi;
    KEYBDINPUT ki;
    HARDWAREINPUT hi;
  };
} INPUT, *PINPUT;
typedef struct tagMOUSEINPUT {
  LONG dx;
  LONG dy;
  DWORD mouseData;
  DWORD dwFlags;
  DWORD time;
  ULONG_PTR dwExtraInfo;
} MOUSEINPUT, *PMOUSEINPUT;
typedef struct tagKEYBDINPUT {
  WORD wVk;
  WORD wScan;
  DWORD dwFlags;
  DWORD time;
  ULONG_PTR dwExtraInfo;
} KEYBDINPUT, *PKEYBDINPUT;
typedef struct tagHARDWAREINPUT {
  DWORD uMsg;
  WORD wParamL;
  WORD wParamH;
} HARDWAREINPUT, *PHARDWAREINPUT;

Although this code is little bit messy, it should be mostly clear to C# developer:

public struct MOUSEINPUT {
  public Int32 dx;
  public Int32 dy;
  public Int32 mouseData;
  public Int32 dwFlags;
  public Int32 time;
  public UInt32 dwExtraInfo;
}
public struct KEYBDINPUT {
  public Int16 wVk;
  public Int16 wScan;
  public Int32 dwFlags;
  public Int32 time;
  public UInt32 dwExtraInfo;
}
public struct HARDWAREINPUT {
  public Int32 uMsg;
  public Int16 wParamL;
  public Int16 wParamH;
}

While this conversion is clear, what is not so clear is what to do with tagINPUT. Solution in C# could look like this:

public struct tagHARDWAREINPUT {
  [FieldOffset(0)]
  public MOUSEINPUT mi;
  [FieldOffset(0)]
  public KEYBDINPUT ki;
  [FieldOffset(0)]
  public HARDWAREINPUT hi;
}

This makes all fields aligned on first byte and thus they behave identically to C++ structure union.