I am trying to mount a Virtual Hard Drive (.VHD) using the Windows 7 API function, but I can't find the relevant function, does one exist?
I am programming in C++ using Visual Studio 2010, for information.
Thanks in advance ;)
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.
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.
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