从磁盘编号中检索虚拟磁盘文件名

当我在diskpart中列出虚拟磁盘时:

DISKPART> list vdisk VDisk ### Disk ### State Type File --------- -------- -------------------- --------- ---- VDisk 0 Disk 2 Attached not open Fixed C:\Disk.vhd 

对我来说有趣的部分是文件名。 如果我知道磁盘号,我试图找到相应的函数,它会给我文件名(在File列下)。

理想情况下,我会给“ \\?\ PhysicalDrive2 ”,我会得到“ C:\ Disk.vhd ”作为结果。

我已经尝试过:

  1. 使用diskpart和解析输出 – 因为它是未记录的格式,它可以随时更改。 这不是我所依赖的。
  2. 常规VHD API – 没有函数将磁盘号作为参数。
  3. Microsoft.Storage.Vds.dll – 有一些枚举通过每个驱动器(例如Service.Providers),但没有属性/函数可以给我源文件的名称。 虽然我现在可以确定例如驱动器D:是虚拟驱动器,但我仍然无法知道附加了哪个.vhd文件。

知道哪个function可能是什么?

以下是在本地计算机上检索虚拟磁盘并打印其信息的两种解决方案。 这两个解决方案演示了如何使用VDS COM对象以本机和托管方式访问这些数据。

管理解决方案

我已经从MSDN文档和Windows 7 SDK(主要是vds.h )创建了一个部分COM Interop。 请注意,COM包装器是部分的,这意味着某些方法尚未被移植。

下面是一个使用.NET COM互操作的托管应用程序:

  • 加载VDS服务
  • 查询虚拟磁盘提供程序
  • 列出每个提供商处理的所有虚拟磁盘:
    • 虚拟磁盘的属性提供其GUID,其完整驱动程序路径,卷大小和磁盘文件 (即C:\Disk.vhd )。
    • 虚拟磁盘也可以作为通用磁盘进行查询,并提供其名称(即\\?\PhysicalDrive1 ),其友好名称和其他属性。

 using System; using System.Runtime.InteropServices; namespace VDiskDumper { class Program { static void Main(string[] args) { // Create the service loader VdsServiceLoader loaderClass = new VdsServiceLoader(); IVdsServiceLoader loader = (IVdsServiceLoader)loaderClass; Console.WriteLine("Got Loader"); // Load the service IVdsService service; loader.LoadService(null, out service); Console.WriteLine("Got Service"); // Wait for readyness service.WaitForServiceReady(); Console.WriteLine("Service is ready"); // Query for vdisk providers IEnumVdsObject providerEnum; service.QueryProviders(VDS_QUERY_PROVIDER_FLAG.VDS_QUERY_VIRTUALDISK_PROVIDERS, out providerEnum); Console.WriteLine("Got Providers"); // Iterate while (true) { uint fetched; object unknown; providerEnum.Next(1, out unknown, out fetched); if (fetched == 0) break; // Cast to the required type IVdsVdProvider provider = (IVdsVdProvider)unknown; Console.WriteLine("Got VD Provider"); Dump(provider); } Console.ReadKey(); } private static void Dump(IVdsVdProvider provider) { // Query for the vdisks IEnumVdsObject diskEnum; provider.QueryVDisks(out diskEnum); Console.WriteLine("Got VDisks"); // Iterate while (true) { uint fetched; object unknown; diskEnum.Next(1, out unknown, out fetched); if (fetched == 0) break; // Cast to the required type IVdsVDisk vDisk = (IVdsVDisk)unknown; // Get the vdisk properties VDS_VDISK_PROPERTIES vdiskProperties; vDisk.GetProperties(out vdiskProperties); Console.WriteLine("-> VDisk Id=" + vdiskProperties.Id); Console.WriteLine("-> VDisk Device Name=" + vdiskProperties.pDeviceName); Console.WriteLine("-> VDisk Path=" + vdiskProperties.pPath); // Get the associated disk IVdsDisk disk; provider.GetDiskFromVDisk(vDisk, out disk); // Get the disk properties VDS_DISK_PROP diskProperties; disk.GetProperties(out diskProperties); Console.WriteLine("-> Disk Name=" + diskProperties.pwszName); Console.WriteLine("-> Disk Friendly=" + diskProperties.pwszFriendlyName); } } } [ComImport, Guid("118610b7-8d94-4030-b5b8-500889788e4e"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface IEnumVdsObject { void Next(uint numberOfObjects, [MarshalAs(UnmanagedType.IUnknown)] out object objectUnk, out uint numberFetched); void Skip(uint NumberOfObjects); void Reset(); void Clone(out IEnumVdsObject Enum); } [ComImport, Guid("07e5c822-f00c-47a1-8fce-b244da56fd06"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface IVdsDisk { void GetProperties(out VDS_DISK_PROP diskProperties); void GetPack(); // Unported method void GetIdentificationData(IntPtr lunInfo); void QueryExtents(); // Unported method void slot4(); void SetFlags(); // Unported method void ClearFlags(); // Unported method } [ComImport, Guid("0818a8ef-9ba9-40d8-a6f9-e22833cc771e"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface IVdsService { [PreserveSig] int IsServiceReady(); [PreserveSig] int WaitForServiceReady(); void GetProperties(); // Unported method void QueryProviders(VDS_QUERY_PROVIDER_FLAG mask, out IEnumVdsObject providers); void QueryMaskedDisks(out IEnumVdsObject disks); void QueryUnallocatedDisks(out IEnumVdsObject disks); void GetObject(); // Unported method void QueryDriveLetters(); // Unported method void QueryFileSystemTypes(out IntPtr fileSystemTypeProps, out uint numberOfFileSystems); void Reenumerate(); void Refresh(); void CleanupObsoleteMountPoints(); void Advise(); // Unported method void Unadvise(); // Unported method void Reboot(); void SetFlags(); // Unported method void ClearFlags(); // Unported method } [ComImport, Guid("e0393303-90d4-4a97-ab71-e9b671ee2729"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface IVdsServiceLoader { void LoadService([In, MarshalAs(UnmanagedType.LPWStr)] string machineName, out IVdsService vdsService); } [ComImport, Guid("1e062b84-e5e6-4b4b-8a25-67b81e8f13e8"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface IVdsVDisk { void Open(); // Unported method void GetProperties(out VDS_VDISK_PROPERTIES pDiskProperties); void GetHostVolume(); // Unported method void GetDeviceName(); // Unported method } [ComImport, Guid("b481498c-8354-45f9-84a0-0bdd2832a91f"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface IVdsVdProvider { void QueryVDisks(out IEnumVdsObject ppEnum); void CreateVDisk(); // Unported method void AddVDisk(); // Unported method void GetDiskFromVDisk(IVdsVDisk pVDisk, out IVdsDisk ppDisk); void GetVDiskFromDisk(IVdsDisk pDisk, out IVdsVDisk ppVDisk); } [ComImport, Guid("9c38ed61-d565-4728-aeee-c80952f0ecde")] public class VdsServiceLoader { } [StructLayout(LayoutKind.Explicit)] public struct Signature { [FieldOffset(0)] public uint dwSignature; [FieldOffset(0)] public Guid DiskGuid; } [StructLayout(LayoutKind.Sequential)] public struct VDS_DISK_PROP { public Guid Id; public VDS_DISK_STATUS Status; public VDS_LUN_RESERVE_MODE ReserveMode; public VDS_HEALTH health; public uint dwDeviceType; public uint dwMediaType; public ulong ullSize; public uint ulBytesPerSector; public uint ulSectorsPerTrack; public uint ulTracksPerCylinder; public uint ulFlags; public VDS_STORAGE_BUS_TYPE BusType; public VDS_PARTITION_STYLE PartitionStyle; public Signature dwSignature; [MarshalAs(UnmanagedType.LPWStr)] public string pwszDiskAddress; [MarshalAs(UnmanagedType.LPWStr)] public string pwszName; [MarshalAs(UnmanagedType.LPWStr)] public string pwszFriendlyName; [MarshalAs(UnmanagedType.LPWStr)] public string pwszAdaptorName; [MarshalAs(UnmanagedType.LPWStr)] public string pwszDevicePath; } [StructLayout(LayoutKind.Sequential)] public struct VIRTUAL_STORAGE_TYPE { public uint DeviceId; public Guid VendorId; } [StructLayout(LayoutKind.Sequential)] public struct VDS_VDISK_PROPERTIES { public Guid Id; public VDS_VDISK_STATE State; public VIRTUAL_STORAGE_TYPE VirtualDeviceType; public ulong VirtualSize; public ulong PhysicalSize; [MarshalAs(UnmanagedType.LPWStr)] public String pPath; [MarshalAs(UnmanagedType.LPWStr)] public String pDeviceName; public DEPENDENT_DISK_FLAG DiskFlag; public bool bIsChild; [MarshalAs(UnmanagedType.LPWStr)] public String pParentPath; } public enum DEPENDENT_DISK_FLAG { DEPENDENT_DISK_FLAG_NONE = 0x00000000, DEPENDENT_DISK_FLAG_MULT_BACKING_FILES = 0x00000001, DEPENDENT_DISK_FLAG_FULLY_ALLOCATED = 0x00000002, DEPENDENT_DISK_FLAG_READ_ONLY = 0x00000004, DEPENDENT_DISK_FLAG_REMOTE = 0x00000008, DEPENDENT_DISK_FLAG_SYSTEM_VOLUME = 0x00000010, DEPENDENT_DISK_FLAG_SYSTEM_VOLUME_PARENT = 0x00000020, DEPENDENT_DISK_FLAG_REMOVABLE = 0x00000040, DEPENDENT_DISK_FLAG_NO_DRIVE_LETTER = 0x00000080, DEPENDENT_DISK_FLAG_PARENT = 0x00000100, DEPENDENT_DISK_FLAG_NO_HOST_DISK = 0x00000200, DEPENDENT_DISK_FLAG_PERMANENT_LIFETIME = 0x00000400, } public enum VDS_DISK_STATUS { VDS_DS_UNKNOWN = 0, VDS_DS_ONLINE = 1, VDS_DS_NOT_READY = 2, VDS_DS_NO_MEDIA = 3, VDS_DS_FAILED = 5, VDS_DS_MISSING = 6, VDS_DS_OFFLINE = 4 } public enum VDS_HEALTH { VDS_H_UNKNOWN = 0, VDS_H_HEALTHY = 1, VDS_H_REBUILDING = 2, VDS_H_STALE = 3, VDS_H_FAILING = 4, VDS_H_FAILING_REDUNDANCY = 5, VDS_H_FAILED_REDUNDANCY = 6, VDS_H_FAILED_REDUNDANCY_FAILING = 7, VDS_H_FAILED = 8, VDS_H_REPLACED = 9, VDS_H_PENDING_FAILURE = 10, VDS_H_DEGRADED = 11 } public enum VDS_LUN_RESERVE_MODE { VDS_LRM_NONE = 0, VDS_LRM_EXCLUSIVE_RW = 1, VDS_LRM_EXCLUSIVE_RO = 2, VDS_LRM_SHARED_RO = 3, VDS_LRM_SHARED_RW = 4 } public enum VDS_PARTITION_STYLE { VDS_PST_UNKNOWN = 0, VDS_PST_MBR = 1, VDS_PST_GPT = 2 } public enum VDS_QUERY_PROVIDER_FLAG { VDS_QUERY_SOFTWARE_PROVIDERS = 0x1, VDS_QUERY_HARDWARE_PROVIDERS = 0x2, VDS_QUERY_VIRTUALDISK_PROVIDERS = 0x4 } public enum VDS_STORAGE_BUS_TYPE { VDSBusTypeUnknown = 0, VDSBusTypeScsi = 0x1, VDSBusTypeAtapi = 0x2, VDSBusTypeAta = 0x3, VDSBusType1394 = 0x4, VDSBusTypeSsa = 0x5, VDSBusTypeFibre = 0x6, VDSBusTypeUsb = 0x7, VDSBusTypeRAID = 0x8, VDSBusTypeiScsi = 0x9, VDSBusTypeSas = 0xa, VDSBusTypeSata = 0xb, VDSBusTypeSd = 0xc, VDSBusTypeMmc = 0xd, VDSBusTypeMax = 0xe, VDSBusTypeFileBackedVirtual = 0xf, VDSBusTypeMaxReserved = 0x7f } public enum VDS_VDISK_STATE { VDS_VST_UNKNOWN = 0, VDS_VST_ADDED, VDS_VST_OPEN, VDS_VST_ATTACH_PENDING, VDS_VST_ATTACHED_NOT_OPEN, VDS_VST_ATTACHED, VDS_VST_DETACH_PENDING, VDS_VST_COMPACTING, VDS_VST_MERGING, VDS_VST_EXPANDING, VDS_VST_DELETED, VDS_VST_MAX } } 

原生解决方案

下面是一个使用VDS COM接口的本机应用程序:

  • 加载VDS服务
  • 查询虚拟磁盘提供程序
  • 列出每个提供商处理的所有虚拟磁盘:
    • 虚拟磁盘的属性提供其GUID,其完整驱动程序路径,卷大小和磁盘文件 (即C:\Disk.vhd )。
    • 虚拟磁盘也可以作为通用磁盘进行查询,并提供其名称(即\\?\PhysicalDrive1 ),其友好名称和其他属性。

 #include "initguid.h" #include "vds.h" #include  #pragma comment( lib, "ole32.lib" ) #pragma comment( lib, "rpcrt4.lib" ) // Simple macro to release non-null interfaces. #define _SafeRelease(x) {if (NULL != x) { x->Release(); x = NULL; } } void exploreVDiskProvider(IVdsVdProvider *pVdProvider); int __cdecl main(void) { HRESULT hResult; ULONG ulFetched = 0; BOOL bDone = FALSE; IVdsServiceLoader *pLoader = NULL; IVdsService *pService = NULL; IEnumVdsObject *pProviderEnum = NULL; IUnknown *pUnknown = NULL; IVdsVdProvider *pVdProvider = NULL; // Initialize COM hResult = CoInitialize(NULL); if (FAILED(hResult)) goto bail; // For this, get a pointer to the VDS Loader hResult = CoCreateInstance(CLSID_VdsLoader, NULL, CLSCTX_LOCAL_SERVER, IID_IVdsServiceLoader, (void **) &pLoader); if (FAILED(hResult)) goto bail; printf("Loading VDS Service...\n"); // Launch the VDS service. hResult = pLoader->LoadService(NULL, &pService); // We're done with the Loader interface at this point. _SafeRelease(pLoader); if (FAILED(hResult)) goto bail; // Wait for service to be ready hResult = pService->WaitForServiceReady(); if (FAILED(hResult)) goto bail; printf("VDS Service Loaded\n"); // Query for virtual disk providers hResult = pService->QueryProviders(VDS_QUERY_VIRTUALDISK_PROVIDERS, &pProviderEnum); if (FAILED(hResult)) goto bail; printf("Querying providers...\n"); // Iterate over virtual disk providers while(1) { ulFetched = 0; hResult = pProviderEnum->Next(1, &pUnknown, &ulFetched); if (FAILED(hResult)) { break; } if (hResult == S_FALSE) { break; } // Cast the current value to a virtual disk provider hResult = pUnknown->QueryInterface(IID_IVdsVdProvider, (void **) &pVdProvider); if (FAILED(hResult)) goto bail; printf("VDS Virtual Disk Provider Found\n"); exploreVDiskProvider(pVdProvider); _SafeRelease(pVdProvider); _SafeRelease(pUnknown); } getchar(); return 0; bail: printf("Failed hr=%x\n", hResult); return 1; } void exploreVDiskProvider(IVdsVdProvider *pVdProvider) { HRESULT hResult; ULONG ulFetched = 0; IEnumVdsObject *pVDiskEnum = NULL; IVdsVDisk *pVDisk = NULL; IUnknown *pUnknown = NULL; IVdsVolume *pVolume = NULL; VDS_VDISK_PROPERTIES vdiskProperties = { 0 }; TCHAR *uuid = NULL; IVdsDisk *pDisk = NULL; VDS_DISK_PROP diskProperties = { 0 }; // Query the disks handled by the provider hResult = pVdProvider->QueryVDisks(&pVDiskEnum); if (FAILED(hResult)) goto bail; printf("Querying virtual disks...\n"); // Iterate over virtual disks while(1) { ulFetched = 0; hResult = pVDiskEnum->Next(1, &pUnknown, &ulFetched); if (hResult == S_FALSE) { break; } if (FAILED(hResult)) goto bail; // Cast the current value to a disk hResult = pUnknown->QueryInterface(IID_IVdsVDisk, (void **) &pVDisk); if (FAILED(hResult)) goto bail; printf("Virtual disk Found\n"); // Get the disk's properties and display some of them hResult = pVDisk->GetProperties(&vdiskProperties); if (FAILED(hResult)) goto bail; // Convert the GUID to a string UuidToString(&vdiskProperties.Id, (RPC_WSTR *) &uuid); // Dump some properties printf("-> Disk Id=%ws\n", uuid); printf("-> Disk Device Name=%ws\n", vdiskProperties.pDeviceName); printf("-> Disk Path=%ws\n", vdiskProperties.pPath); // Get the disk instance from the virtual disk hResult = pVdProvider->GetDiskFromVDisk(pVDisk, &pDisk); if (FAILED(hResult)) goto bail; _SafeRelease(pVDisk); _SafeRelease(pUnknown); // Get the disk's properties and display some of them hResult = pDisk->GetProperties(&diskProperties); if (FAILED(hResult)) goto bail; printf("-> Disk Name=%ws\n", diskProperties.pwszName); printf("-> Disk Friendly Name=%ws\n", diskProperties.pwszFriendlyName); } return; bail: printf("Failed hr=%x\n", hResult); } 

虚拟磁盘API没有官方托管的.NET包装器。 所以你目前有三个选择:

  1. 运行dos命令并抓取控制台响应,您不想这样做,因为它不是一个稳定的API。

  2. 使用Server 2008中添加的Microsoft.Storage.Vds.dll。您可以使用.NETreflection器来检查API。 然而,这也是非官方的,因为它没有文档,因此可能在服务包等没有警告的情况下改变。

  3. 使用官方C API 。 在官方托管包装类发布并记录之前,我会建议这样做。 如上所述, 完整的API文档包含您需要的一切。 我建议围绕这个API编写一个简化的C包装器dll,它可以满足您的需要,而不是更多。 然后,PInvoke你的包装库。

P /调用GetStorageDependencyInformation将提供严格的VHD API解决方案。 虽然此函数不将驱动器号作为输入参数,但是包装器方法将会。 包装器方法将驱动器号转换为“ \\\\。\\ PhysicalDriveN ”forms的字符串,该字符串传递给CreateFile ,结果句柄传递给GetStorageDependencyInformation 。 类似的包装器方法将输入单个char驱动器号。
以下代码从非托管示例转换为C#:

 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 } } 

好像你需要使用IEnumVdsObject,但我不确定你使用的操作系统是什么?

无法在我的计算机上测试虚拟磁盘。 但是你可以尝试WMI查询。

例如。 我可以使用以下代码获取分区信息

 using System; using System.Management; using System.Windows.Forms; namespace WMISample { public class MyWMIQuery { public static void Main() { try { ManagementObjectSearcher searcher = new ManagementObjectSearcher("root\\CIMV2", "SELECT * FROM Win32_DiskPartition"); foreach (ManagementObject queryObj in searcher.Get()) { Console.WriteLine("-----------------------------------"); Console.WriteLine("Win32_DiskPartition instance"); Console.WriteLine("-----------------------------------"); Console.WriteLine("Access: {0}", queryObj["Access"]); Console.WriteLine("Availability: {0}", queryObj["Availability"]); Console.WriteLine("BlockSize: {0}", queryObj["BlockSize"]); Console.WriteLine("Bootable: {0}", queryObj["Bootable"]); Console.WriteLine("BootPartition: {0}", queryObj["BootPartition"]); Console.WriteLine("Caption: {0}", queryObj["Caption"]); Console.WriteLine("ConfigManagerErrorCode: {0}", queryObj["ConfigManagerErrorCode"]); Console.WriteLine("ConfigManagerUserConfig: {0}", queryObj["ConfigManagerUserConfig"]); Console.WriteLine("CreationClassName: {0}", queryObj["CreationClassName"]); Console.WriteLine("Description: {0}", queryObj["Description"]); Console.WriteLine("DeviceID: {0}", queryObj["DeviceID"]); Console.WriteLine("DiskIndex: {0}", queryObj["DiskIndex"]); Console.WriteLine("ErrorCleared: {0}", queryObj["ErrorCleared"]); Console.WriteLine("ErrorDescription: {0}", queryObj["ErrorDescription"]); Console.WriteLine("ErrorMethodology: {0}", queryObj["ErrorMethodology"]); Console.WriteLine("HiddenSectors: {0}", queryObj["HiddenSectors"]); Console.WriteLine("Index: {0}", queryObj["Index"]); Console.WriteLine("InstallDate: {0}", queryObj["InstallDate"]); Console.WriteLine("LastErrorCode: {0}", queryObj["LastErrorCode"]); Console.WriteLine("Name: {0}", queryObj["Name"]); Console.WriteLine("NumberOfBlocks: {0}", queryObj["NumberOfBlocks"]); Console.WriteLine("PNPDeviceID: {0}", queryObj["PNPDeviceID"]); if(queryObj["PowerManagementCapabilities"] == null) Console.WriteLine("PowerManagementCapabilities: {0}", queryObj["PowerManagementCapabilities"]); else { UInt16[] arrPowerManagementCapabilities = (UInt16[])(queryObj["PowerManagementCapabilities"]); foreach (UInt16 arrValue in arrPowerManagementCapabilities) { Console.WriteLine("PowerManagementCapabilities: {0}", arrValue); } } Console.WriteLine("PowerManagementSupported: {0}", queryObj["PowerManagementSupported"]); Console.WriteLine("PrimaryPartition: {0}", queryObj["PrimaryPartition"]); Console.WriteLine("Purpose: {0}", queryObj["Purpose"]); Console.WriteLine("RewritePartition: {0}", queryObj["RewritePartition"]); Console.WriteLine("Size: {0}", queryObj["Size"]); Console.WriteLine("StartingOffset: {0}", queryObj["StartingOffset"]); Console.WriteLine("Status: {0}", queryObj["Status"]); Console.WriteLine("StatusInfo: {0}", queryObj["StatusInfo"]); Console.WriteLine("SystemCreationClassName: {0}", queryObj["SystemCreationClassName"]); Console.WriteLine("SystemName: {0}", queryObj["SystemName"]); Console.WriteLine("Type: {0}", queryObj["Type"]); } } catch (ManagementException e) { MessageBox.Show("An error occurred while querying for WMI data: " + e.Message); } } } } 

它提供了与您的机器相关的所有内容。 您可以尝试使用该工具在您的计算机上获取命名空间和类: http : //www.microsoft.com/downloads/details.aspx?familyid = 2cc30a64-ea15-4661-8da4-55bbc145c30e&displaylang = en