• Programmatically mount a Microsoft Virtual Hard Drive (VHD)


    By Pixy https://stackoverflow.com/questions/24396644/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

  • 相关阅读:
    正则
    springboot整合rabbitmq(fanout广播模式)
    docker 安装rabbitmq
    centos7安装rabbitmq
    rabbitmq报错{:query, :rabbit@master1, {:badrpc, :timeout}}
    Linux永久修改hostname
    thread dump日志文件分析
    模板方法模式
    装饰器模式
    springboot集成redis,压测报错;
  • 原文地址:https://www.cnblogs.com/liujx2019/p/12736677.html
Copyright © 2020-2023  润新知