About the Author

Travis Schilling is focused on the Rich Client Stack of .NET that manifests his programming expertise in software technologies like C#, WPF, Silverlight, ADO.Net, WCF, and HTML5. His software expertise crosses the latest genre of cutting edge computing devices like the Microsoft Surface and the XBOX Kinect. After graduating from Neumont University in Salt Lake City, Utah with a Bachelor’s degree in Computer Science, Travis became a Software Engineer at InterKnowlogy in Carlsbad, CA. Travis has an expertise in NUI (The Natural User Interface) having built numerous multi-touch and gesture based interfaces for software applications. Travis is a Windows Developer 4 Microsoft Certified Professional Developer. When not architecting, designing and building software, Travis is often found in the gym, conquering the galaxy in StarCraft 2 or playing his bass guitar. Travis’ loves are his Nissan 370z and hanging with friends and family.

Copying Files After a Successful Build With Robocopy on VS2010

The Problem
In one of the latest projects I’ve been working on, I needed to be able to interchange data providers. We decided to use Prism and MEF to load up the concrete instance of our IDataProvider at runtime, and created a separate project to contain the XML based implementation of that provider. Since we need a concrete instance to debug I wanted the latest .dll and .pdb of the XML data provider project to be copied into a Modules folder in the app’s output directory after it has successfully built. At first I thought I would use xcopy to copy the files, but after seeing that it has been deprecated, I switched to using Robocopy (which turned out to be just as easy). Once I figured what tool I would use to copy the files, I needed to figure out where to run the command from and I found 2 options.

Option 1: Project Post-build event
The quickest option I found was to enter the Robocopy command into the Post-build Event Command Line box in the project properties. Since Robocopy comes with Windows Vista and on you can open the Command Prompt and type robocopy /? to see everything that it is capable of. The command I used to copy the .dll and .pdb files was the following:
robocopy “$(TargetDir)\” “$(SolutionDir)\Application\$(OutDir)\Modules” $(TargetName).dll $(TargetName).pdb

With that command entered, I saved and then built the project, but the build was not successful and displayed an error staying robocopy exited with a code of 1. Wondering why I received this error, I went to the application’s output directory to find, to my surprise, that the Modules folder had been created and both the .dll and .pdb files had been copied successfully to that folder. Searching around for an answer I found this stackoverflow post explaining that unlike every other command line tool that returns a 0 when successful (which is what Visual Studio expects), robocopy returns a 1 when successful. So after adding a check to exit with a code of 0 if the error level was 1, it then built successfully.

Option 2: MSBuild Extension AfterBuild
On the stackoverflow post, mentioned above, there was an answer that recommended using the Robocopy task in the MSBuild Extension Pack as an AfterBuild target. I found this idea very intriguing (especially since it appeared to handle the return code of 1 issue) and attempted to use it to accomplish the same copying task. After a few hours of working with it I found that I could only get it functioning installing the MSBuild Extension Pack3.5 (even though I am on an x64 machine and building a .Net 4.0 project). I then edited my .csproj file and added the following code, which does the exact same thing as the post-build command, at the bottom of the file. After reloading and building the project, the files were copied to the Modules folder.

<Import Project="$(MSBuildExtensionsPath)\ExtensionPack\MSBuild.ExtensionPack.tasks"/>
<Target Name="AfterBuild">
	<ItemGroup>
		<OutputFiles Include="$(TargetName).dll"/>
		<OutputFiles Include="$(TargetName).pdb"/>
	</ItemGroup>
	<MSBuild.ExtensionPack.FileSystem.RoboCopy Source="$(TargetDir)\" Destination="$(SolutionDir)\Application\$(OutDir)\Modules" Files="@(OutputFiles)">
		<Output TaskParameter="ExitCode" PropertyName="Exit" />
		<Output TaskParameter="ReturnCode" PropertyName="Return" />
	</MSBuild.ExtensionPack.FileSystem.RoboCopy>
	<Message Text="ExitCode = $(Exit)"/>
	<Message Text="ReturnCode = $(Return)"/>
</Target>

The Decision
While Option 2 is very cool and clean looking, I decided to stick with Option 1 for the following reasons:

  1. Option 2 would require all the developers on the project to install the MSBuild Extension pack (not difficult at all but time consuming and annoying if your builds are failing and you didn’t know you needed the 3rd party pack)
  2. Writing the Post-build (Option 1) command was much quicker
  3. If any other developer is wondering how the files are being copied into the Modules folder (or needs to change it), with Option 1 they can quickly and easily look at (and change) the Post-build event in the properties window, but with Option 2 they have to know to go edit the .csproj file and then search it to find the AfterBuild target code

SpeechRecognitionEngine Grammar Choices and Updating them Dynamically

The Microsoft Speech Platform provides a great speech recognition engine. I’ve been using it with the Microsoft Kinect to add voice command functionality to existing Kinect enabled WPF applications. The SDK is located here, and once installed you just need to add a reference to Microsoft.Speech.dll, which is located at C:\Program Files\Microsoft Speech Platform SDK\Assembly.

Static Choices
Once you have the SDK and assembly referenced, the process of specifying what words or phrases you want the SpeechRecognitionEngine to look for is extremely straight forward and easy. Just specify your collection of Choices, create a new GrammarBuilder and append the Choices to it, create a Grammar and provide it with the GrammarBuilder, and finally load that Grammar into the SpeechRecognitionEngine. You can then point the SpeechRecognitionEngine to your audio source and tell it to RecognizeAsync.

var sre = new SpeechRecognitionEngine(ri);
var currentChoices = new Choices();
currentChoices.Add("red");
currentChoices.Add("show blue square");

var gb = new GrammarBuilder
{
     Culture = _ri.Culture
};
gb.Append(currentChoices);

sre.LoadGrammar(new Grammar(gb));

Dynamic Choices
If you know all of the possible command choices from the beginning and never need them to change, then this is as far as you need to go. I, however, wanted to be able to change what choices were valid based on what area of the application I was in. I had hoped it would be as simple as adding and removing choices for the collection, but there isn’t any remove functionality in Choices, GrammarBuilder, or Grammar. On the SpeechRecognitionEngine I did find an UnloadGrammar method so I figured I could just keep a collection of my currently valid choices, create a new Grammar from those, unload the old Grammar, and then load the new one. When I ran the application I ran into some very weird results. Calling UnloadGrammar would take a very long time to execute (it took 3 minutes for one try). Once it got past that point loading the new grammar worked, but the amount of time it was taking was unbearable and I would not be able to use it if there was always the possibility of the application freezing up for that long just to change the available audio choices. So after a long time searching I finally decided to see what MSDN had to say about the UnloadGrammar and LoadGrammar methods and found this page. It is for Office 2007 R2 but the example it provided put me on the right track.

It turns out that when the SpeechRecognitionEngine is running, any changes to the grammar need to occur when the engine is ready for the changes. To get the engine ready you need to call RequestRecognizerUpdate and pass a custom object (that contains what action you want to do and the related data) into the method as a UserToken.

sre.RequestRecognizerUpdate(new UpdateGrammarRequest
								{
									RequestType = GrammarRequestType.UnloadGrammar,
									Grammar = _currentGrammar
								});
sre.RequestRecognizerUpdate(new UpdateGrammarRequest
								{
									RequestType = GrammarRequestType.LoadGrammar,
									Grammar = _currentGrammar
								});

You also need to subscribe to the RecognizerUpdateReached event on the engine, and in that event handler you can call the UnloadGrammar and LoadGrammar methods which will then execute immediately.

private void RecognizerUpdateReached(object sender, RecognizerUpdateReachedEventArgs e)
{
	var request = e.UserToken as UpdateGrammarRequest;
	if (request == null)
		return;

	switch (request.RequestType)
	{
		case GrammarRequestType.LoadGrammar:
			sre.LoadGrammar(request.Grammar);
			break;
		case GrammarRequestType.UnloadGrammar:
			sre.UnloadGrammar(request.Grammar);
			break;
		default:
			throw new ArgumentOutOfRangeException();
	}
}

By doing this, you still end up with a tiny bit of lag between calling RequestRecognizerUpdate and having the RecognizerUpdateReached event fire, but it is only ever a couple seconds instead of minutes.

Remote Debugging from Visual Studio 2010

In my latest project I was running into an issue where running my installed application on a test machine was crashing before it could even startup, but it ran perfectly when installed on my machine. I was almost to the point of taking the time to install Visual Studio 2010 on the test machine, when my coworker, Bryan Coon, reminded me of the Remote Debugging capabilities of VS and recommended trying that first.

I started off using Danny Warren’s Remote Debugging post to get both my machine(on domain) and the test machine(off domain) enabled so that I could Attach to Process (Ctrl+Alt+P) from VS 2010 on my machine. Here are the main points that I gathered from it:

  • 3 instances of the same username needed to exist as administrators (and have been logged into at least once)
    1. The domain username on my machine (domain\travis). This is the username that Visual Studio is run under.
    2. The machine username on my machine (MyMachine\travis)
    3. The machine username on the test machine (TestMachine\travis). This is the username that the remote application is run under.
  • The Visual Studio 2010 Remote Debugging Monitor needed to be installed on the test machine
    • Use the setup program that matches the OS (x86, x64, ia64)
    • I ran the application instead of setting it up as a service, so I needed to make sure it ran as an administrator
  • Everything from the bin\Debug folder of the application must be copied to the test machine.

Once the Remote Debugging Monitor was started, I was able to view all the running processes in VS by entering the name of the server that the Remote Debugging Monitor started (travis@TestMachine) into the Qualifier box.

In most cases this would have allowed me to then attach to my running application and hit debug points. My application, however, crashed before the application even became available in the list of available processes.

So the next step was to get Visual Studio 2010 configured on my machine to start the application on the remote (test) machine when I started the application with debugging (F5). I found what was needed here. All that was required was to modify the following properties in the Debug section of the application properties screen:

  • Select Start external program and specify the path to the application on the remote computer
  • Check Use remote machine and specify the remote machine

The gotcha I ran into was that again the remote machine name is the server name that the Remote Debugging Monitor started not the actual machine name.

With these final steps completed I was able to start the application with debugging and immediately found my issue. While this process took a little bit of time to setup, it saved a bunch of time that would have been spent installing Visual Studio 2010 and allowed me to keep the test machine clean of all developer tools. So if I run into an issue like this again I will definitely think to try Remote Debugging right away.

Delivering the Art of Lunch

Here at InterKnowlogy we have this great program called RECESS where we get to take a few hours each week to try our hand at new technologies. One of our leads, Dan Hanan, posted a great little read on what RECESS actually is so I won’t go into any more detail about it.

Background
One of the best ways, we’ve found, to learn a new technology is to utilize it in an application in order to find its strengths, weaknesses, etc. Being a bunch of Software Engineers we have a tendency to be obsessive and compulsive in almost everything we do, and when that is paired with pickiness over certain types of food, deciding upon where to go to lunch as a group becomes very time consuming (almost longer than actually eating the food). So back in the spring of this year a couple of other devs and myself decided we wanted to learn more about ASP.Net MVC, Silverlight 4 (with RIA), and Entity Framework 4, and decided on creating a lunch decision service using these technologies (kill 2 birds with 1 stone and have fun doing it). We also decided that we needed a good name for this application before we could start, and since InterKnowlogy’s slogan had recently changed to Delivering the Art of Software, we decided to play with it and call our application the DAL (Delivering the Art of Lunch).

Scenario
The most important thing we’ve learned from other RECESS projects is to keep the finished project as simple as possible otherwise it won’t ever be finished. So we decided to create a service that would send out an email to all the registered users, at a specified time in the morning, to see if they will be joining the group for lunch. In the email is a link to an MVC page where they say yes or no. A little later on everyone who says that they are in for lunch then receive another email with a link to another MVC page where they can choose their top 3 restaurant choices(the restaurants are an intersection of all the preferred restaurants of the users joining in for lunch), and a little later an email stating the restaurant choice is sent out to everyone participating in lunch. It is then up to the people involved on whether they are going to abide by the choice or not.

We decided to use the Silverlight client to be where we register users, create/update/delete restaurants, and choose which restaurants the user is ok with going to for lunch, and the ASP.Net MVC site is where the users specify if they are available for lunch and their top 3 restaurant choices. It also shows who has said they are joining in and what the final restaurant choice is.

After a few weeks of work we had an Alpha version that we wanted to try out with our coworkers. So we deployed it to a server, and sent out an email letting everyone know about it. With it being Alpha we expected to run into a few issues, but within the 1st day we hit one issue that brought the whole thing down. Our owner, Tim Huckaby, loves to hear about new things we’re working on and try them out. So he joined in, added 5 top restaurants in the world (that none of us can afford let alone get to over lunch time), and made only those 5 his preferred restaurants. The next day when the process started and he said he was in for lunch (even though he doesn’t eat lunch with us), the resulting intersection of preferred restaurants was empty, and we weren’t able to use the application when it never provided restaurants to choose from.

Fixing the bug
While we have given Tim some much deserved crap over the restaurants he chose, he did find a very damaging bug that needed to be fixed. Our end result was if the restaurant intersection didn’t return any results then choose up to 5 of the most popular preferred restaurants, and if there still weren’t any the service randomly chooses 5 restaurants for everyone to vote on.

After a long hiatus, I finally got the bug fix along with a number of other refactorings up again and we’ll see how long it can stand. :)

Finally
The overall learning experience was pretty positive. Entity Framework makes development against a simple database extremely easy, and in the Silverlight world, pairing that with RIA services gives you the same functionality on the client side. One issue with RIA that I ran into is the fact that any extra methods you create to extend the DomainService is very limited to the parameter types that can be used. It is extremely powerful for basic CRUD functionality, but it takes work to get more complex things functioning. ASP.Net MVC is really powerful and something that I will need to delve into more in the future.

More RECESS rambles to come.

Stream HTML5 Video from Azure Blob Storage

I’ve been looking into what needs to be done in order to stream videos hosted in Microsoft Azure’s Blob storage with the HTML5 <video> control. Once I got over a few little hiccups, the process was very straight forward.

The Process

I followed the Video On The Web section of the online book Dive Into HTML5 by Mark Pilgrim for the overall process. It provides a couple nice pictures stating which browser supports which codec. I was disappointed with the fact that there isn’t one codec supported by all the mainstream browsers, so to support all you have to have at least 2.

I decided that I would take my video and encode it in the H.264 and OGG formats. NOTE: The document above is a bit old but the steps provide a good idea of what to set to accomplish the encoding. Once the two versions were ready I created a simple .html page and hosted it in my local IIS just to test out that I had done the encoding correctly. Below is what I had.

<!DOCTYPE html>
<html>
<body>
<h1>Test</h1>
<video width="576" height="320" controls>
	<source src="tbbt_s1e1.mp4"  type='video/mp4; codecs="avc1.42e01e, mp4a.40.2"'>
	<source src="tbbt_s1e1.ogv"  type='video/ogg; codecs="theora, vorbis"'>
</video>
</body>
</html>

The HTML5 <video> control is really straight forward to use. The controls attribute tells the browser to display its prebuilt controls and there are 2 ways to specify the source video file(s). The first way only uses one file so if the browser doesn’t support it, then you can’t watch. The second way is what I followed, and it allowed me to provide multiple video files allowing the browser to choose the codec it supports.

When I viewed the page the video player controls showed up, but the videos didn’t work. The important thing I missed was to make sure IIS had the correct MIME type defined for the videos (MIME Types Rear Their Ugly Head section of the document above). After adding the following MIME types to the root IIS node the videos played.

Extension MIME type
.ogv video/ogv
.mp4 video/mp4

 
With the videos functioning, I then moved on to hosting the video files in my Blob Azure Development Storage and pointing to those files. Previously I had created a little application to upload files to Blob storage, so I used it to upload the files instead of any of the Azure file explorer applications.

I then pointed the .html file above to the Azure urls and got the player again with the video not working.

<!DOCTYPE html>
<html>
<body>
<h1>Test</h1>
<video width="576" height="320" controls>
	<source src="http://127.0.0.1:10000/devstoreaccount1/videocontainer/c625cff5-6f03-4e89-a8b3-43f29b97f14b.mp4"  type='video/mp4; codecs="avc1.42e01e, mp4a.40.2"'>
	<source src="http://127.0.0.1:10000/devstoreaccount1/videocontainer/4e3f4531-e3d2-407f-8a78-bea8d540d537.ogv"  type='video/ogg; codecs="theora, vorbis"'>
</video>
</body>
</html>

Turns out I ran into the exact same MIME type issue. My application didn’t set the Content Type property of each Blob to the correct type so Azure wouldn’t allow it to be streamed out, but it could be downloaded. To quickly change this I used Azure Storage Explorer to point to my Development Storage and change the Content Type of each of the files to their respective MIME type specified in the table above.

I then browsed to the .html file again and the videos played!

Codec Issues
When encoding the video to the H.264 and OGG formats I ran into a few issues. First I used HandBrake and Firefogg (requires Firefox) respectively to encode the files, but while HandBrake worked, the file Firefogg provided didn’t have audio when played in Firefox. I then switched to using ffmpeg2theora hoping that would fix the issue, but it didn’t. I then tried encoding them for the WebM codec, but that still didn’t work. In a final attempt I took the H.264(.mp4) file that HandBrake output(since it was working great) and used Miro Video Converter to convert it to a OGG(.ogv) file. This new version worked in Firefox, so what I thought was an issue with Firefox or my hosting just turned out to be an encoding problem.

I also ran into an issue viewing the H.264 version in IE9, but it turned out to be a Compatibility View issue that I documented here

I still have a ton to learn about Azure Storage, HTML5 Video and Codecs, but I think this was a good start.

HTML5 Video and IE9 Compatibility View

When messing around with HTML5 and its <video> I had it working great in IE9 on my machine using the H.264 codec. I then had some of my coworkers attempt to view my .html file which I had hosted in IIS on my machine. Everyone could view the page but the video player only showed up for one guy. I was baffled and started on a wild goose chase trying to figure out what was different between my machine, the one that worked and all the other machines.

Finally I started comparing the HTML being displayed in each IE9 browser using the Developer Tools (these can be accessed easily by pressing F12).

In the 2 browsers that showed the video, the HTML looked totally correct. In the others the <video> tag was closed prematurely and the <!DOCTYPE html> tag at the top was a comment instead of valid HTML. Then I noticed what the issue was. My page was being shown in IE9 Compatibility View which doesn’t support HTML5, which totally explained the weird behavior.

It turns out that the default settings in IE9 are to view all intranet sites in Compatibility View. This seems totally backwards to me as a developer as I am usually dealing with the latest and greatest (which Compatibility View is not). To change this press alt, then choose Tools, select Compatibility View settings, and then uncheck Display intranet sites in Compatibility View.

With this change on everyone’s machines they can now all view the HTML5 video hosted in my IIS.

XamlReader, Loose ResourceDictionary Files, and the ParserContext

In a few WPF projects that I have been on I have needed to load in loose ResourceDictionary files to provide different runtime styling. When there isn’t any external content being referenced (ie. images, videos, etc…) it is as simple as calling XamlReader.Load and then merging the dictionary into the application’s resources:

var resourceDictionary = XamlReader.Load(fileStream) as ResourceDictionary;
if(resourceDictionary != null)
{
    Resources.MergedDictionaries.Add(resourceDictionary)
}

When external content is being referenced there is the possibility that the XamlReader won’t be able to find those files, even if they are in the exact same folder as the ResourceDictionary files. To solve this issue, you will need to create a ParserContext and set its BaseUri to the root folder containing the files. For example, if the ResourceDictionary and content files are located in a folder called RuntimeResources, which is in the same folder as the application’s exe, then the BaseUri needs to point to that RuntimeResources folder. Then when the XamlReader loads the ResourceDictionary, it uses the provided ParserContext to know where to look for the actual files. NOTE: In the ResourceDictionary you will still need to include the root folder (RuntimeResources) at the beginning of the uri otherwise it will look in the parent directory for the desired file.

Below is the related code:

C#

var applicationDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
if(!String.IsNullOrEmpty(applicationDirectory ))
{

    var runtimeResourcesDirectory = Path.Combine(applicationDirectory , "RuntimeResources");
    var pc = new ParserContext
    {
        BaseUri = new Uri(runtimeResourcesDirectory , UriKind.Absolute)
    };
    if(Directory.Exists(runtimeResourcesDirectory ))
    {
        foreach (string resourceDictionaryFile in Directory.GetFiles(runtimeResourcesDirectory , "*.xaml"))
        {
            using (Stream s = File.Open(resourceDictionaryFile, FileMode.Open, FileAccess.Read))
            {
                try
                {
                    var resourceDictionary = XamlReader.Load(s, pc) as ResourceDictionary;
                    if (resourceDictionary != null)
                    {
                        Resources.MergedDictionaries.Add(resourceDictionary);
                    }
                }
                catch
                {
                    MessageBox.Show("Invalid xaml: " + resourceDictionaryFile);
                }
            }
        }
    }
}

Resource Dictionary

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
			    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

	<ImageBrush x:Key="LogoImage"
			  ImageSource="RuntimeResources/logo.png" />

</ResourceDictionary>

Now you’ve got the ability to change your WPF application’s styling at runtime.

Creating and Registering Windows 7 Bootable VHDs

Here at InterKnowlogy we have the benefit of working on a lot of cutting edge technologies. A good deal of our first looks at different technologies involve installing alpha/beta bits that may or may not install or uninstall properly and may or may not play nice with existing technologies that we use in other projects. The simple way to keep from destabilizing your system is in creating a Virtual PC and running it with any number of applications (VMware, VirtualBox, Windows Virtual PC, etc…). Doing this keeps your existing system clean and free from any possibilities of errors occurring. However with most Virtual PCs they are utilizing virtual drivers and not running straight off the physical hardware so it doesn’t function as quickly as your main OS, and on top of that you have to share RAM between the two. If you need to switch back and forth continuously between the two then this is just something you have to deal with. However, if you are able to have everything on just the Virtual PC AND are running Windows 7 (for both your actual OS and VPC) then you have another option.

Windows Virtual PC utilizes a file with the extension .vhd for its virtual hard drive. It contains everything for the entire OS and instead of using the VHD through Windows Virtual PC, in Windows 7 you can register that VHD into the boot menu and, on startup, boot straight into it like it is an OS installed on your machine.

Create Bootable VHD

  1. Open Computer Management and switch to Disk Management View
  2. Select Create VHD from the Action menu
  3. Choose location, disk format (can be either Fixed or Dynamic), disk size (30GB Min Recommended), and finish. The creation process might take 5-10 min. There won’t be any extra dialog, just a progress bar at the bottom.
  4. Right-click on the new disk that shows up in Disk Management and initialize it with a MBR partition style.
  5. Right-click on the initialized partition and select New Simple Volume. Go through the wizard. The only thing that you will want to change is the Volume Label on the Format Partition screen. Make a note of the drive letter that is assigned on the 3rd screen in the dialog as you will use this later.

Install Windows 7

  1. Install the Windows Automated Installation Kit for Windows 7 to get access to the ImageX utility which is located at C:\Program Files\Windows AIK\Tools in either the x86 or amd64 folders.
  2. In Disk Management make sure that the VHD that was created and initialized is attached (Action->Attach VHD)
  3. Open a command prompt and change directory to either C:\Program Files\Windows AIK\Tools\x86 (if you are installing Windows 7 32bit) or C:\Program Files\Windows AIK\Tools\amd64 (if you are installing Windows 7 64bit).
  4. Then run the following command: imagex /apply d:\sources\install.wim 1 x:\
    1. d:\sources\install.wim is the location of the “install.wim” file in the Windows 7 media (mounted ISO file or DVD)
    2. 1 is the image index of the OS. 1 can be assumed, however to check what it is you can run the command: imagex /info d:\sources\install.wim and look at the Image Index
    3. x:\ is the drive letter for the attached VHD that you made note of earlier
  5. Once the ImageX utility has finished, run the following command to add this drive to the boot menu as the default boot OS: bcdboot x:\Windows
    1. Using this command will make this your default OS to boot into on the boot screen. The easiest way to change this is to get to Advanced system settings (via the computer properties screen), select Settings… in the Startup and Recovery section, and then change the value in the Default operating system dropdown.

Change the OS name in the boot loader

The next time you start up your machine, you’ll notice there is now an additional Windows 7. The big question is which one is your main OS and which is your new bootable VHD. So before you restart or shutdown your machine you’ll want to rename your bootable VHD description.

  1. Open a command prompt and run the following command to see all the boot loader entries: bcdedit
    Example Windows Boot Loader Entries
    The top Windows Boot Loader section is of a bootable VHD and the bottom one is for the main OS.
  2. Find the Windows Boot Loader entry that has its device value pointing to your vhd file. This will be the actual location (and while in your main OS will start with vhd)  ie. vhd=[C:]\VHDs\Win764bit.vhd
  3. Copy the identifier value (including the curly braces) for that entry ie. {5e6085cb-8f65-11de-8f7c-92487039f837}
  4. Enter the following command to change the description: bcdedit /set {5e6085cb-8f65-11de-8f7c-92487039f837} description “New Description”
    1. {5e6085cb-8f65-11de-8f7c-92487039f837} is the identifier you copied
    2. “New Description” is the value you want to have show up in the boot menu. Make sure to keep the quotation marks if you use spaces.

Now when the boot loader shows up you’ll be able to tell which OS is which.

Now you can have the “sandboxed” benefit of a Virtual PC with the performance of a non-virtual OS.

Resources

Scott Hanselman’s Computer Zen

Aviraj Ajgekar’s Blog

Virtual Varia