Retrieving virtual disk file name from disk number

后端 未结 4 1434
囚心锁ツ
囚心锁ツ 2020-12-25 08:53

When I list virtual disks within diskpart:

DISKPART> list vdisk

  VDisk ###  Disk ###  State                 Type       File
  ---------  --------  -----         


        
4条回答
  •  無奈伤痛
    2020-12-25 09:14

    P/Invoking the GetStorageDependencyInformation will provide a strictly VHD API solution. While this function does not take a drive number as an input parameter, a wrapper method will. The wrapper method converts a drive number to a string of the form "\\\\.\\PhysicalDriveN" which is passed to CreateFile and the resultant handle is passed to GetStorageDependencyInformation. A similar wrapper method will take an input of a single char drive letter.
    The following code was translated to C# from an unmanaged example:

    using DWORD = System.UInt32;
    using ULONG = System.UInt32;
    
    using System;
    using System.Collections.Generic;
    using System.Runtime.InteropServices;
    using Microsoft.Win32.SafeHandles;
    using System.IO;
    
    namespace VhdTest
    {
        class Program
        {
            static void Main(string[] args)
            {
                String[] arr;
                arr = VirtualDisk.GetDependentVolumePaths('e');
                arr = VirtualDisk.GetDependentVolumePaths(1);
    
            }
        }
    
    
        class VirtualDisk
        {
            #region [ Native ]
    
            #region [ Constants ]
            const DWORD ERROR_INSUFFICIENT_BUFFER = 122;
            const DWORD ERROR_SUCCESS = 0;
    
            const DWORD GENERIC_READ = 0x80000000;
    
            const DWORD FILE_SHARE_READ = 1;
            const DWORD FILE_SHARE_WRITE = 2;
            const DWORD OPEN_EXISTING = 3;
    
            const DWORD FILE_ATTRIBUTE_NORMAL = 0x00000080;
            const DWORD FILE_FLAG_BACKUP_SEMANTICS = 0x02000000;
            #endregion 
    
            #region [ Enums ]
            [Flags]
            enum DEPENDENT_DISK_FLAG
            {
                DEPENDENT_DISK_FLAG_NONE = 0x00000000,
    
                //
                // Multiple files backing the virtual storage device
                //
                DEPENDENT_DISK_FLAG_MULT_BACKING_FILES = 0x00000001,
                DEPENDENT_DISK_FLAG_FULLY_ALLOCATED = 0x00000002,
                DEPENDENT_DISK_FLAG_READ_ONLY = 0x00000004,
    
                //
                //Backing file of the virtual storage device is not local to the machine
                //
                DEPENDENT_DISK_FLAG_REMOTE = 0x00000008,
    
                //
                // Volume is the system volume
                //
                DEPENDENT_DISK_FLAG_SYSTEM_VOLUME = 0x00000010,
    
                //
                // Volume backing the virtual storage device file is the system volume
                //
                DEPENDENT_DISK_FLAG_SYSTEM_VOLUME_PARENT = 0x00000020,
                DEPENDENT_DISK_FLAG_REMOVABLE = 0x00000040,
    
                //
                // Drive letters are not assigned to the volumes
                // on the virtual disk automatically.
                //
                DEPENDENT_DISK_FLAG_NO_DRIVE_LETTER = 0x00000080,
                DEPENDENT_DISK_FLAG_PARENT = 0x00000100,
    
                //
                // Virtual disk is not attached on the local host
                // (instead attached on a guest VM for instance)
                //
                DEPENDENT_DISK_FLAG_NO_HOST_DISK = 0x00000200,
    
                //
                // Indicates the lifetime of the disk is not tied
                // to any system handles
                //
                DEPENDENT_DISK_FLAG_PERMANENT_LIFETIME = 0x00000400
            }
    
            [Flags]
            enum GET_STORAGE_DEPENDENCY_FLAG
            {
                GET_STORAGE_DEPENDENCY_FLAG_NONE = 0x00000000,
    
                // Return information for volumes or disks hosting the volume specified
                // If not set, returns info about volumes or disks being hosted by
                // the volume or disk specified
                GET_STORAGE_DEPENDENCY_FLAG_HOST_VOLUMES = 0x00000001,
                GET_STORAGE_DEPENDENCY_FLAG_PARENTS = GET_STORAGE_DEPENDENCY_FLAG_HOST_VOLUMES,
                //  The handle provided is to a disk, not volume or file
                GET_STORAGE_DEPENDENCY_FLAG_DISK_HANDLE = 0x00000002,
    
            }
    
            enum STORAGE_DEPENDENCY_INFO_VERSION
            {
                STORAGE_DEPENDENCY_INFO_VERSION_UNSPECIFIED = 0,
                STORAGE_DEPENDENCY_INFO_VERSION_1 = 1,
                STORAGE_DEPENDENCY_INFO_VERSION_2 = 2,
            }
            #endregion
    
            #region [ Structures ]
            [StructLayout(LayoutKind.Sequential)]
            struct STORAGE_DEPENDENCY_INFO_TYPE_1
            {
                DEPENDENT_DISK_FLAG DependencyTypeFlags;
                ULONG ProviderSpecificFlags;
                VIRTUAL_STORAGE_TYPE VirtualStorageType;
            }
    
            [StructLayout(LayoutKind.Sequential)]
            struct STORAGE_DEPENDENCY_INFO_TYPE_2
            {
                public DEPENDENT_DISK_FLAG DependencyTypeFlags;
                public ULONG ProviderSpecificFlags;
                public VIRTUAL_STORAGE_TYPE VirtualStorageType;
                public ULONG AncestorLevel;
                public IntPtr DependencyDeviceName;
                public IntPtr HostVolumeName;
                public IntPtr DependentVolumeName;
                public IntPtr DependentVolumeRelativePath;
            }
    
            [StructLayout(LayoutKind.Explicit)]
            struct STORAGE_DEPENDENCY_INFO_Union
            {
                [FieldOffset(0)]
                STORAGE_DEPENDENCY_INFO_TYPE_1 Version1Entries;
                [FieldOffset(0)]
                STORAGE_DEPENDENCY_INFO_TYPE_2 Version2Entries;
            }
    
            [StructLayout(LayoutKind.Sequential)]
            struct STORAGE_DEPENDENCY_INFO
            {
                public STORAGE_DEPENDENCY_INFO_VERSION Version;
                public ULONG NumberEntries;
                public STORAGE_DEPENDENCY_INFO_Union Union;
            }
    
            [StructLayout(LayoutKind.Sequential)]
            struct VIRTUAL_STORAGE_TYPE
            {
                public ULONG DeviceId;
                public Guid VendorId;
            }
            #endregion
    
            #region [ PInvokes ]
            [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
            public static extern SafeFileHandle CreateFile(string lpFileName,
                DWORD dwDesiredAccess,
                DWORD dwShareMode,
                IntPtr lpSecurityAttributes,
                DWORD dwCreationDisposition,
                DWORD dwFlagsAndAttributes,
                IntPtr hTemplateFile);
    
    
            [DllImport("virtdisk.dll", SetLastError = true, CharSet = CharSet.Unicode)]
            static extern DWORD GetStorageDependencyInformation(SafeHandle ObjectHandle,
                GET_STORAGE_DEPENDENCY_FLAG Flags,
                ULONG StorageDependencyInfoSize,
                IntPtr StorageDependencyInfo,
                ref ULONG SizeUsed);
            #endregion
    
            #endregion
    
            #region [ Managed Methods ]
            public static String[] GetDependentVolumePaths(char driveLetter)
            {
                driveLetter = Char.ToUpper(driveLetter);
                if (driveLetter < 'A' || driveLetter > 'Z')
                {
                    String paramName = "driveLetter";
                    String message = "Drive letter must fall in range [a-zA-Z]";
                    throw new ArgumentOutOfRangeException(paramName, message);
                }
                String fileName = String.Format(@"\\.\{0}:\", driveLetter);
                return getDependentVolumePaths(fileName);
            }
    
            public static String[] GetDependentVolumePaths(UInt32 driveNumber)
            {
                // TODO:  Per SO, isn't max drive 15? 
                // http://stackoverflow.com/questions/327718/how-to-list-physical-disks
                if (driveNumber > 9)
                {
                    String paramName = "driveNumber";
                    String message = "Drive number must be <= 9";
                    throw new ArgumentOutOfRangeException(paramName, message);
                }
                String fileName = String.Format(@"\\.\PhysicalDrive{0}", driveNumber);
                return getDependentVolumePaths(fileName);
            }
    
            static unsafe String[] getDependentVolumePaths(String fileName)
            {
                DWORD dwDesiredAccess = GENERIC_READ;
                DWORD dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
                DWORD dwCreationDisposition = OPEN_EXISTING;
                DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS;
    
                SafeHandle driveHandle = null;
                STORAGE_DEPENDENCY_INFO info = new STORAGE_DEPENDENCY_INFO();
                info.Version = STORAGE_DEPENDENCY_INFO_VERSION.STORAGE_DEPENDENCY_INFO_VERSION_2;
                IntPtr ptr;
    
                try
                {
                    driveHandle = CreateFile(fileName,
                        dwDesiredAccess, //GENERIC_READ,
                        dwShareMode,
                        IntPtr.Zero,
                        dwCreationDisposition,
                        dwFlagsAndAttributes,
                        IntPtr.Zero);
                    if (driveHandle.IsInvalid)
                    {
                        return null;
                    }
    
                    GET_STORAGE_DEPENDENCY_FLAG flags = GET_STORAGE_DEPENDENCY_FLAG.GET_STORAGE_DEPENDENCY_FLAG_NONE;
                    flags |= GET_STORAGE_DEPENDENCY_FLAG.GET_STORAGE_DEPENDENCY_FLAG_PARENTS;
                    if (fileName.ToUpper().Contains("PHYSICAL"))
                        flags |= GET_STORAGE_DEPENDENCY_FLAG.GET_STORAGE_DEPENDENCY_FLAG_DISK_HANDLE;
    
                    DWORD infoSize = (DWORD)Marshal.SizeOf(info);
    
                    byte[] infoByteArray;
                    DWORD cbSize = 0;
                    DWORD opStatus;
    
                    #region [ Pull STORAGE_DEPENDENCY_INFO into byte array  ]
                    infoByteArray = new byte[infoSize];
                    fixed (byte* p1 = infoByteArray)
                    {
                        ptr = (IntPtr)p1;
                        Marshal.StructureToPtr(info, ptr, true);
                        opStatus = GetStorageDependencyInformation(driveHandle, flags, infoSize, ptr, ref cbSize);
    
                        if (opStatus == ERROR_INSUFFICIENT_BUFFER)
                        {
                            infoSize = cbSize;
                            cbSize = 0;
    
                            infoByteArray = new byte[infoSize];
                            fixed (byte* p2 = infoByteArray)
                            {
                                ptr = (IntPtr)p2;
                                Marshal.StructureToPtr(info, ptr, true);
                                opStatus = GetStorageDependencyInformation(driveHandle, flags, infoSize, ptr, ref cbSize);
                            }
                        }
    
                    }
    
                    #endregion
                    if (opStatus != ERROR_SUCCESS)
                    {
                        //
                        // This is most likely due to the disk not being a mounted VHD.
                        //
                        return null;
                    }
                }
                finally
                {
                    if (driveHandle != null && !driveHandle.IsInvalid && !driveHandle.IsClosed)
                    {
                        driveHandle.Close();
                    }
                }
    
                List pathList = new List();
                info = (STORAGE_DEPENDENCY_INFO)Marshal.PtrToStructure(ptr, typeof(STORAGE_DEPENDENCY_INFO));
                //STORAGE_DEPENDENCY_INFO_TYPE_2 sdi2 = new STORAGE_DEPENDENCY_INFO_TYPE_2();
                STORAGE_DEPENDENCY_INFO_TYPE_2* p = (STORAGE_DEPENDENCY_INFO_TYPE_2*)&info.Union;
                for (DWORD i = 0; i < info.NumberEntries; i++, p++)
                {
                    ptr = (IntPtr)p;
                    STORAGE_DEPENDENCY_INFO_TYPE_2 sdi2 = (STORAGE_DEPENDENCY_INFO_TYPE_2)Marshal.PtrToStructure(ptr, typeof(STORAGE_DEPENDENCY_INFO_TYPE_2));
                    String str1 = Marshal.PtrToStringUni(sdi2.DependencyDeviceName);
                    String str2 = Marshal.PtrToStringUni(sdi2.HostVolumeName);
                    String str3 = Marshal.PtrToStringUni(sdi2.DependentVolumeName);
                    String relativePath = Marshal.PtrToStringUni(sdi2.DependentVolumeRelativePath);
                    String fullPath = Path.GetFullPath(relativePath);
                    pathList.Add(fullPath);
                }
                return pathList.ToArray();
            }
            #endregion
        }
    
    }
    

提交回复
热议问题