Mounting VHDs from Managed Code

Mounting VHDs from Managed Code

  • Comments 3

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: http://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: http://www.danielmoth.com/Blog/2007/08/uac-settings-in-vb.html

Cheers,
Ben

Leave a Comment
  • Please add 4 and 8 and type the answer here:
  • Post
  • hey..

    you have got a really superb blog here.. i have thoroughly enjoyed reading it.. i have added it to my blogroll ..

    Prakhar

  • Hi Ben, Can you do the same from VBScript? M

  • Thanks for the code. It is very useful. I have been playing with it and have two questions:

    1) When will the ReadOnly flag be implemented?

    2) Is it possible to mount a VHD on a computer that doesn't have any Virtual PC/Server software on it?

    Using VhdMount.exe /m only seems to work on something that already has Virtual Server installed. It throws an error that says:

    Failed to plug the Virtual Hard Disk (VHD). Virtual Disk Service (VDS) is not available. This option uses VDS to mount the volumes on the VHD. Use /p to plug in the VHD and then use Disk Manager to mount the volumes.

    Then VhdMount.exe /p just fails with: Failed to plug in the VHD.

    Any advice for mounting a VHD on a computer that doesn't have virtual server installed?

    Thanks

Page 1 of 1 (3 items)