Programmatically mount a Microsoft Virtual Hard Drive (VHD)
This is an old question but it still has no answer so I'll provide one in case someone stumble upon it like I did.
Attaching the VHD
For the complete Reference on MSDN [VHD Reference]: http://msdn.microsoft.com/en-us/library/windows/desktop/dd323700(v=vs.85).aspx
OPEN_VIRTUAL_DISK_PARAMETERS openParameters; openParameters.Version = OPEN_VIRTUAL_DISK_VERSION_1; openParameters.Version1.RWDepth = OPEN_VIRTUAL_DISK_RW_DEPTH_DEFAULT; VIRTUAL_STORAGE_TYPE storageType; storageType.DeviceID = VIRTUAL_STORAGE_TYPE_DEVICE_VHD; storageType.VendorId = VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT; ATTACH_VIRTUAL_DISK_PARAMETERS attachParameters; attachParameters.Version = ATTACH_VIRTUAL_DISK_VERSION_1; HANDLE vhdHandle; if (OpenVirtualDisk(&openStorageType, "{VHD PATH GOES HERE}", VIRTUAL_DISK_ACCESS_ALL, OPEN_VIRTUAL_DISK_FLAG_NONE, &openParameters, &vhdHandle) != ERROR_SUCCESS) { // If return value of OpenVirtualDisk isn't ERROR_SUCCESS, there was a problem opening the VHD } // Warning: AttachVirtualDisk requires elevation if (AttachVirtualDisk(vhdHandle, 0, ATTACH_VIRTUAL_DISK_FLAG_PERMANENT_LIFETIME, 0, &attachParameters, 0) != ERROR_SUCCESS) { // If return value of AttachVirtualDisk isn't ERROR_SUCCESS, there was a problem attach the disk }
VHD successfully attached, now it'll show up like any other physical disks and a drive letter will automatically be assigned to the volume(s) contained in the VHD. If you'd like to choose what drive letter is used to mount it, keep reading.
Assigning a drive letter
First, add the ATTACH_VIRTUAL_DISK_FLAG_NO_DRIVE_LETTER
flag to your AttachVirtualDisk call so it won't do this automatic letter assigning. Next, you'll have to find the volume path of the VHD volumes [it has this format: \\?\Volume{GUID}]:
wchar_t physicalDrive[MAX_PATH]; ULONG bufferSize = sizeof(physicalDrive); GetVirtualDiskPhysicalPath(vhdHandle, &bufferSize, physicalDrive);
Now you'll have the physical path of your attached VHD in physical drive in the following format: \\.\PhysicalDrive# where # is the drive number you'll need to find your VHD volumes with FindFirstVolume/FindNextVolume. Extract the number and convert it to an integer and you'll be ready for the next piece of code:
char volumeName[MAX_PATH]; DWORD bytesReturned; VOLUME_DISK_EXTENTS diskExtents; HANDLE hFVol = FindFirstVolume(volumeName, sizeof(volumeName)); bool hadTrailingBackslash = false; do { // I had a problem where CreateFile complained about the trailing \ and // SetVolumeMountPoint desperately wanted the backslash there. I ended up // doing this to get it working but I'm not a fan and I'd greatly // appreciate it if someone has any further info on this matter int backslashPos = strlen(volumeName) - 1; if (hadTrailingBackslash = volumeName[backslashPos] == '\\') { volumeName[backslashPos] = 0; } HANDLE hVol = CreateFile(volumeName, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if (hVol == INVALID_HANDLE_VALUE) { return; } DeviceIoControl(hVol, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, NULL, 0, &diskExtents, sizeof(diskExtents), &bytesReturned, NULL); // If the volume were to span across multiple physical disks, you'd find // more than one Extents here but we don't have to worry about that with VHD // Note that 'driveNumber' would be the integer you extracted out of // 'physicalDrive' in the previous snippet if (diskExtents.Extents[0].DiskNumber == driveNumber) { if (hadTrailingBackslash) { volumeName[backslashPos] = '\\'; } // Found volume that's on the VHD, let's mount it with a letter of our choosing. // Warning: SetVolumeMountPoint requires elevation SetVolumeMountPoint("H:\\", volumeName); } } while (FindNextVolume(hFVol, volumeName, sizeof(volumeName))); FindVolumeClose(hFVol);
Don't forget these includes and link to this library:
#define WINVER _WIN32_WINNT_WIN7 #include <windows.h> #include <winioctl.h> #include <virtdisk.h> #pragma comment(lib, "virtdisk.lib")
Disclaimer: This is something I was doing in a C# codebase, I translated the code to C/C++ because of the question but haven't tried to actually compile it. If you find errors in the code, please edit it or let me know so I can do it.
Edits: Typos, includes and lib, forgot FindVolumeClose, elevation warnings