Mounting VHDs from Managed Code

When Virtual Server 2005 R2 SP1 was released it included the VHDMount tool - that came with a DLL to allow you to control it programmatically.  Unfortunately we were rather light with the documentation / sample code for this.  So today I would like to show you how to drive VHD mounting from managed code.

To do this I will be creating a small application called 'VHDMounter'.  It will have a simple user interface like this:

vhdmounter

To help with tracking things in the code I have named the TextBox "VHDTextBox" and the buttons "MountButton" and "UnmountButton" respectively.  Once the basic user interface is built here is the code that you need to drive the application:

VB:

 Imports System.Runtime.InteropServices
  
 Public Class Form1
  
     'Setup the VHD_FLAGS enumeration.  Data copied from VHDMount.h
     Enum VHD_FLAGS
         VHD_NORMAL
         VHD_NW_MAPPED           ' Unused
         VHD_MOUNT_AS_READONLY   ' Unused
         VHD_FORCE_UNMOUNT
     End Enum
  
     'Create interop for the MountVHD call off of vhdmount.dll
     <DllImport("C:\\Program Files\\Microsoft Virtual Server\\Vhdmount\\vhdmount.dll", CharSet:=CharSet.Auto)> _
     Public Shared Function MountVHD(ByVal VHDFileName As String, ByVal Flags As Integer) As Integer
     End Function
  
     'Create interop for the MountVHD call off of vhdmount.dll
     <DllImport("C:\\Program Files\\Microsoft Virtual Server\\Vhdmount\\vhdmount.dll", CharSet:=CharSet.Auto)> _
     Public Shared Function UnmountVHD(ByVal VHDFileName As String, ByVal Flags As Integer) As Integer
     End Function
  
     'Mount the selected VHD when the user clicks on the MountButton
     Private Sub MountButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MountButton.Click
  
         Dim result As Integer
  
         'Call MountVHD with the parameter of the text in the text box
         result = MountVHD(VHDTextBox.Text, VHD_FLAGS.VHD_NORMAL)
  
         'Handle result code
         If result = 0 Then
             MsgBox(Chr(34) & VHDTextBox.Text & Chr(34) & " was successfully mounted.")
         Else
             MsgBox("An error was encountered attempting to mount " & Chr(34) & VHDTextBox.Text & Chr(34) & "." & Chr(10) & Chr(10) & "The error code returned was: " & result & ".")
         End If
  
     End Sub
  
     'Unmount the selected VHD when the user clicks on the UnmountButton
     Private Sub UnmountButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles UnmountButton.Click
  
         Dim result As Integer
  
         'Call UnmountVHD with the parameter of the text in the text box
         result = UnmountVHD(VHDTextBox.Text, VHD_FLAGS.VHD_NORMAL)
  
         'Handle result code
         If result = 0 Then
             MsgBox(Chr(34) & VHDTextBox.Text & Chr(34) & " was successfully unmounted.")
         Else
             MsgBox("An error was encountered attempting to unmount " & Chr(34) & VHDTextBox.Text & Chr(34) & "." & Chr(10) & Chr(10) & "The error code returned was: " & result & ".")
         End If
  
     End Sub
  
 End Class

C#:

 using System;
 using System.Collections.Generic;
 using System.ComponentModel;
 using System.Data;
 using System.Drawing;
 using System.Linq;
 using System.Text;
 using System.Windows.Forms;
 using System.Runtime.InteropServices; 
  
 namespace VHDMount_C
 {
     public partial class Form1 : Form
     {
  
         // Setup the VHD_FLAGS enumeration.  Data copied from VHDMount.h
         enum VHD_FLAGS
         {
             VHD_NORMAL,
             VHD_NW_MAPPED,          // Unused
             VHD_MOUNT_AS_READONLY,  // Unused
             VHD_FORCE_UNMOUNT
         } ;
  
         // Create interop for the MountVHD call off of vhdmount.dll
         [DllImport("C:\\Program Files\\Microsoft Virtual Server\\Vhdmount\\vhdmount.dll", CharSet = CharSet.Auto)]
         static extern UInt32 MountVHD(String VHDFileName, UInt32 Flags);
  
         // Create interop for the MountVHD call off of vhdmount.dll
         [DllImport("C:\\Program Files\\Microsoft Virtual Server\\Vhdmount\\vhdmount.dll", CharSet = CharSet.Auto)]
         static extern UInt32 UnmountVHD(String VHDFileName, UInt32 Flags);
  
         public Form1()
         {
             InitializeComponent();
         }
  
         // Mount the selected VHD when the user clicks on the MountButton
         private void MountButton_Click(object sender, EventArgs e)
         {
             UInt32 result;
  
             // Call MountVHD with the parameter of the text in the text box
             result = MountVHD(VHDTextBox.Text, (UInt32)VHD_FLAGS.VHD_NORMAL);
  
             // Handle result code
             if (result == 0) 
                 MessageBox.Show((char)34 + VHDTextBox.Text + (char)34 + " was successfully mounted.");
             else
                 MessageBox.Show("An error was encountered attempting to mount " + (char)34 + VHDTextBox.Text + (char)34 + "." + (char)10 + (char)10 + "The error code returned was: " + result + ".");
         }
  
         // Unmount the selected VHD when the user clicks on the UnmountButton
         private void UnmountButton_Click(object sender, EventArgs e)
         {
             UInt32 result;
  
             // Call UnmountVHD with the parameter of the text in the text box
             result = UnmountVHD(VHDTextBox.Text, (UInt32)VHD_FLAGS.VHD_NORMAL);
  
             // Handle result code
             if (result == 0)
                 MessageBox.Show((char)34 + VHDTextBox.Text + (char)34 + " was successfully unmounted.");
             else
                 MessageBox.Show("An error was encountered attempting to unmount " + (char)34 + VHDTextBox.Text + (char)34 + "." + (char)10 + (char)10 + "The error code returned was: " + result + ".");
         }
  
  
     }
 }

Let us have a dig into what is happening here:

  • The first thing to do is to create an enum for VHD_FLAGS.  This information is grabbed directly from the VHDMount.h file in the vhdmount directory from where Virtual Server is installed.

  • Next you need to create interop code for 'MountVHD' and 'UnmountVHD' on vhdmount.dll.  Note that while I am doing a full path reference to the copy of vhdmount.dll that is included with my installation of Virtual Server - you probably just want to make a local copy of this file for your project (also note that the Virtual Server EULA does grant you redistribution rights if you want to include this in a formal product).

  • Finally hookup some basic code for click events on MountButton and UnmountButton to try and mount / unmount the virtual hard disk specified in VHDTextBox.  In this code I do not do any checking on the text that I am passing to vhdmount.dll because I am lazy and vhdmount.dll does a very good job of checking the validity of the string anyway.  The result code will always be '0' if the operation is successful.  Any other result code means a failure of some kind.  To look up the meaning of a result code go to here: https://msdn2.microsoft.com/en-us/library/ms681382(VS.85).aspx

Two final things to be aware of:

  • This code was written using Visual Studio 2008 - I make no guarantees of compatibility with other versions of Visual Studio.

  • In order for this code to work it needs to be running with Administrative privilege.  You can manually launch with administrative privilege - or you can manifest it to require administrative privilege.  You can read how to do this with Visual Studio 2008 here: https://www.danielmoth.com/Blog/2007/08/uac-settings-in-vb.html

Cheers,

Ben