Showing posts with label coding. Show all posts
Showing posts with label coding. Show all posts

Monday, June 22, 2009

Attaching a VHD to a Windows 7/Server 2008 host from managed code

This past weekend I had "fun" working on a project to attach VHD files to a Windows 7/Server 2008 host machine. My aim was to have a C# app be able to do this and then read the files off the VHD...

It turns out the easiest part was opening and attaching the VHD file. The VHD APIs are pretty straight-forward, and a simple managed wrapper lets you call these from C#. (I chose a Managed C++ wrapper, but there is a C# wrapper here)

By default AttachVirtualDisk will mount all the volumes on the virtual disk, which is what I wanted. (You could also tell the VHD API to not mount them and do it yourself for the partitions you cared about, but that sounded like a lot of extra work to me...)

Now came the fun - which drive letters were assigned to the mounted partitions on the VHD? It turns out the VHD API doesn't provide this information - the most it will give you is the physical path for the drive device (see GetVirtualDiskPhysicalPath)

I looked around and found some examples of people using Powershell to mount VHDs and figure out the drive letters. Some folks were using the Virtual Disk Service (VDS), which has a managed wrapper in Server 2008 (Microsoft.Storage.Vds.dll) - Taylor Brown talks about this on his blog.

That wouldn't work on Windows 7 though, so I was left considering writing a managed wrapper for the VDS COM interface. My head was beginning to hurt... :)

Luckily I found some hints at using WMI to get the info - using WMI from .NET is not too complicated once you figure out which objects and queries to use. Here's the resulting code (Managed C++) which retrieves the logical drive for the first partition on the VHD:

// Return the logical disk for the VHD's first partition
property String^ LogicalDisk
{
String^ get()
{
String^ physicalPath = this->PhysicalPath; // Calls GetVirtualDiskPhysicalPath API wrapper
String^ logicalDisk = nullptr;

// Use WMI to get the logical drive for the first partition on the VHD disk
RelatedObjectQuery^ q = gcnew RelatedObjectQuery(String::Format("\\\\.\\root\\cimv2:Win32_DiskDrive.DeviceID='{0}'", physicalPath), "Win32_DiskPartition");
ManagementObjectSearcher^ searcher = gcnew ManagementObjectSearcher(q);
String^ firstPartition = nullptr;
for each (ManagementObject^ o in searcher->Get())
{
firstPartition = o->Path->ToString();
break;
}
if (firstPartition != nullptr)
{
// Now see which volumes are related to the partitions
q = gcnew RelatedObjectQuery(firstPartition, "Win32_LogicalDisk");
searcher->Query = q;
for each (ManagementObject^ o in searcher->Get())
{
logicalDisk = o->GetPropertyValue("Name")->ToString();
break;
}
}
return logicalDisk;
}
}

Tuesday, January 06, 2009

Spot the defect!

From this zuneboards post, the Zune New Year's bug. Can you spot what is wrong? :P


year = ORIGINYEAR; /* = 1980 */

while (days > 365)
{
if (IsLeapYear(year))
{
if (days > 366)
{
days -= 366;
year += 1;
}
}
else
{
days -= 365;
year += 1;
}
}

Tuesday, June 10, 2008

Spell-check your code

I find it amusing when I stumble on mis-spelled API functions and structures. The irony is that a gaffe by one programmer becomes a documented interface, and it's often impossible to correct the mistake.

Take for example the PrintProvidor entries in Win32:
http://msdn.microsoft.com/en-us/library/aa506097.aspx

Luckily the person writing the surrounding text was able to use the phrase "print provider".

Friday, May 09, 2008

Fun with pointers

For the software geeks out there... What is the output from this code? (No cheating - compiling this and running it isn't allowed!)


void Func() {

char *c[] = {
"ENTER",
"NEW",
"POINT",
"FIRST" };

char **cp[] = { c+3, c+2, c+1, c };
char ***cpp = cp;

printf("%s", **++cpp );
printf("%s", *--*++cpp+3);
printf("%s", *cpp[-2]+3);
printf("%s", cpp[-1][-1]+1);
}

Thursday, March 06, 2008

3D graphics in Excel

Cutting-edge computer games use different graphics subsystems -- so-called 3D graphics engines. Source (used in Half Life 2), Unreal Engine (Unreal Tournament), idTech 4 (Doom 3), CryENGINE2 (Crysis) or Clever's Paradox engine are well-known among the players and the game industry experts.
It's time to learn a new 3D game engine name: Microsoft Excel.

See the full article here, and be sure to check out the movies too.

My hat is off to you, sir!

Thursday, November 30, 2006

Bjarne Stroustrup interview

Something for the geeks out there: an interview with Bjarne. As Ali G might say "He's the geezer wot gave us C-plusity-plus".
Why's this article interesting? From the subtitle: "the inventor of the C++ programming language, defends his legacy and examines what's wrong with most software code."

Every few weeks there'll be a flare up of the old C/C++-vs-Managed-Code argument on the programming lists at work. It's certainly true that C and C++ both let you shoot yourself in the foot easily (and have nice exploitable security bugs in your code, such as buffer-overflows), but C++ also has the added tendency to introduce really nasty, hard-to-track-down bugs when you don't really understand what's happening under the covers. As long as you know exactly what you and the compiler, and the standard libraries (if you use them) are doing, you'll be fine.

C#/managed code generally isolate you from the nasty details of what's happening under the covers (at least, if you just use managed code and don't need to interoperate with native code). You don't need to worry about the difference between a container of objects and a container of pointers. No smart pointers to use or not use. And generally great built-in standard libraries.

Although I am not a C# and managed code expert, my take (and most other peoples) is that they're definitely a move in the right direction in terms of preventing stupid bugs from having security impacts. No more BO's and memory-management woes. Managed code is not automatically free from security bugs though...

Wednesday, November 22, 2006

More on Allegro

A few days ago I wrote about Scrabble and mentioned the Allegro graphics library.
It turns out that the creator of Allegro, Shawn Hargreaves, is now at Microsoft and has a blog.

He works on XNA Game Studio Express which looks quite interesting. Read his introductory blog post here, and there's lots more info on XNA on his blog.

Saturday, November 18, 2006

Scrabble: Man vs. Machine


The Seattle Times today has a story about recent man-machine match in Seattle. Jim Kramer is the 2006 U.S. Scrabble Open champion, and played a best-of-3 match against RealNetwork's new Scrabble game. Jim managed to beat the computer 2-1, and walked away with the $10,000 prize.

Jim said:




...it was a victory that he wouldn't expect five years from now. The computer programs will be much more sophisticated, he said. "They'll just have much more brute force."


I'm not sure how much stronger Scrabble games will be in 5 years - Scrabble is a fairly simple game for computers to play (unlike, say, Go). The mechanics of the game have documented algorithms that can be used (Appel & Jacobson's "The world's fastest Scrabble program", for example). The tricky bit is the strategy - often playing the highest-scoring move will not ensure a win against a strong human opponent.

This is the algorithm I implemented for fun many years back when I was in university (as a hobby). The project was really fun and had some interesting challenges, the first of which was filling in the few gaps in the above paper so that the algorithm was clear. Other fun things (at least they seemed fun to me at the time):




  • Where to get words from? The most essential part of a Scrabble game is having a good list of words - they should be legal Scrabble words of course. I found a few free word lists online and used them, but had to try to prune out invalid words (proper nouns, acronyms). Eventually I found a nice OWL/OSW word list (I think it was 2-8 letter words) and augmented that with some longer words from my other source. I think in the end I had 130,000+ words.


  • Storing the dictionary in a file. The naive solution is to use a big text file. The program would then read this in and build a DAWG ("directed acyclic word graph" incase you care) for use when searching for words. However this was slow, and the file was huge. So, I started playing with ways to build the DAWG once, and save it as a binary file that was smaller and could be loaded quickly.


  • Compressing the dictionary. It turns out that there is a lot of redundancy in English words, and the DAWG has lots of sub-graphs that are redundant. This means wasted space on the disk (not such a big deal) and wasted memory (more of a big deal). I was coding all this in C/C++ and DJGPP (a free 32-bit compiler and port of the GNU C libraries). This meant I could use more than 640kb in DOS/Windows, but my home machine was not that beefy. (It was a 486SX with 4MB of RAM if I remember right). So, the huge dictionary I was using actually had problems fitting into memory unless I reduced it's size somehow. The solution was to look for the redundant parts of the DAWG and "fold them" onto themselves. Finding matches for sub-graphs was fun, and I had many iterations of my "dictionary builder and packer" tool. Initially it would take an overnight run for it to produce the final output file, but in the end it did its job in an hour or so! :)


  • Graphics. Since the DJGPP compiler and libraries I was using were pretty basic, I didn't have fancy Windows-style graphics I could use (no menus, windows, etc.) I used the fantastic free graphics library Allegro instead. This still meant I had to cobble together my own menus and code to handle the placement of Scrabble tiles. I also had a feature that would let you ask the computer for "hints". It would basically figure out all the possible moves you could make, and sort them in descending score. You could then drag a scrollbar and flip through all the possible words - really quickly.


  • Strategy. I left this to last and never really did anything wonderful (by this stage I was ready to move on to something else...) My game simply chose the highest-scoring move it could find and played that... It was still pretty hard to beat.


Sadly, the code to my Scrabble game disappeared when I upgraded to a new machine (stupid me for not having enough backups)!