Super User is a question and answer site for computer enthusiasts and power users. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I have an old Windows XP Mode vhd backed up from my previous system, but I'm having difficulty getting it running on the new system.

The vhd is a differencing disk, and its parent is the standard Windows XP Mode base; I still have the old parent, and have verified it is binary identical to the XP Mode base in my new installation of XP Mode.

But in the new system, the path to the differencing disk parent is different than the old.

When I open up the settings for the .vmcx for my old XP mode, and select "Hard Disk 1", the "Virtual hard disk file" is set correctly, but the "Parent Disk:" field is pointing at the wrong path, and I can't see any way to edit it.

Does anyone know how?

share|improve this question
up vote 2 down vote accepted

OK, I solved this problem myself, but it was unreasonably difficult.

The path to the parent is hard-coded inside the .vhd, in several different formats; in my case, both relative and absolute paths, in both ASCII and UTF-16, for 4 total paths. You can get the .vhd file format specification from Microsoft.

But a quick scan with strings or a similar utility (I'm using Cygwin here) that searches for string data can find these offsets more easily than walking the VHD structures:

$ strings -t x Windows\ XP\ Mode-X.vhd | head -200 | grep vhd
40000 ..\..\..\..\..\..\..\other\xp-mode\Windows XP Mode base.vhd
40200 C:\other\xp-mode\Windows XP Mode base.vhd
$ strings -t x -e l Windows\ XP\ Mode-X.vhd | head -200 | grep vhd
40400 ..\..\..\..\..\..\..\other\xp-mode\Windows XP Mode base.vhd
40600 C:\other\xp-mode\Windows XP Mode base.vhd

These strings are stored with lots of null byte padding; I used a hex editor to update the paths to new locations.

But it didn't work; the paths were shown truncated in the Virtual PC settings editor. The string lengths are encoded elsewhere; in my case at 0x4AB, 0x4C3, etc. (I did a hex search for the old path lengths). I updated these lengths, but then the vhd was regarded as invalid by the Virtual PC settings editor. I figured that a checksum was now involved, downloaded the VHD spec, installed Word document viewer so I could read the .doc, and then I wrote the program below. Its output, when handed the path to the vhd, is the updated checksum and the location for the checksum; example output:

opening Windows XP Mode-X.vhd
dynamic header seems to be at 0x200
new checksum: ffffda30 at 0x224

Entering this new checksum with a hex editor made the vhd work, and the old XP mode booted up successfully.

Checksum calculation program:

#include <fcntl.h>
#include <stdio.h>
#include <io.h>
#include <stdlib.h>
#include <unistd.h>

const int checksum_offset = 36;

long long flip_endian_ll(long long x)
    return ((x & 0x00000000000000FFULL) << 56)
        |  ((x & 0x000000000000FF00ULL) << 40)
        |  ((x & 0x0000000000FF0000ULL) << 24)
        |  ((x & 0x00000000FF000000ULL) << 8)
        |  ((x & 0x000000FF00000000ULL) >> 8)
        |  ((x & 0x0000FF0000000000ULL) >> 24)
        |  ((x & 0x00FF000000000000ULL) >> 40)
        |  ((x & 0xFF00000000000000ULL) >> 56);

int die(const char *msg)
    fprintf(stderr, "error: %s\n", msg);

int main(int argc, const char *const *args)
    int f, r;
    long long dyn_ofs;
    unsigned char dyn_header[1024];

    if (argc != 2)
        fprintf(stderr, "expected: .vhd argument\n");
        return 1;

    printf("opening %s\n", args[1]);
    f = open(args[1], O_RDONLY | O_BINARY);
    if (f < 0)
        die("failed open");
    r = lseek(f, 0x10, SEEK_SET);
    if (r < 0)
        die("seek failed");
    r = read(f, &dyn_ofs, sizeof(dyn_ofs));
    if (r != 8)
        die("failed read");
    dyn_ofs = flip_endian_ll(dyn_ofs);
    printf("dynamic header seems to be at 0x%llx\n", dyn_ofs);

    r = lseek(f, dyn_ofs, SEEK_SET);
    if (r < 0)
        die("seek failed");
    r = read(f, dyn_header, sizeof(dyn_header));
    if (r != sizeof(dyn_header))
        die("read of dynamic header failed");

    if (memcmp("cxsparse", dyn_header, 8) != 0)
        die("dynamic header didn't start with cxsparse");

        unsigned long sum = 0;
        int i;

        for (i = checksum_offset; i < checksum_offset + 4; ++i)
            dyn_header[i] = 0;
        for (i = 0; i < sizeof(dyn_header); ++i)
            sum += dyn_header[i];
        sum = ~sum; // flip_endian_l(~sum);
        printf("new checksum: %.8x at 0x%llx\n", sum, dyn_ofs + checksum_offset);
    return 0;

This cost me some hours, but I got through in the end. I'm sure someone will eventually post a VHD editor that does this more easily, but at least I got through to my old XP mode once more.

Update: There's a much easier way to do this, using PowerShell to script some COM objects:

In essence:

$vpc=new-object -com VirtualPC.Application
$VHDChild = $vpc.GetHardDisk("C:\NAV2010.06.10_Diff")
$VHDParent = $vpc.GetHardDisk("\\devnas\Data_Backups SQLCluster1\NAV2010.06.10.vhd")
$VHDChild.Parent = $VHDParent
share|improve this answer
I am pretty sure I would have given up before modifying the VHD files with a hex editor multiple times, reading the VHD spec, and then writing a c++ (?) application to calculate VHD checksums. If I hadn't figured out the "easy" way to do this there is no way I would have gone this far. You sir have inspired me to push further than I would have in the past, +1. – Chris Magnuson Aug 27 '12 at 19:55

Alternatively, if you would rather not write C++ code to manipulate the .VHD file:

...from Virtual PC, select 'Virtual Disk Wizard', 'Edit an existing virtual disk' and select the faulty differencing disk, you'll receive the following message:

"The parent virtual hard disk has been deleted or has been moved from its previous location. Please select the new location of the parent virtual hard disk."

Click [Change...] and locate the parent disk.

share|improve this answer

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .