When I list virtual disks within diskpart:
DISKPART> list vdisk
VDisk ### Disk ### State Type File
--------- -------- -----
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<String> pathList = new List<String>();
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
}
}
There is no official managed .NET wrapper for the virtual disk APIs. So you currently have three options:
Run the dos command and scrape the console response, which you don't want to do as it is not a stable API.
UseMicrosoft.Storage.Vds.dll
that was added in Server 2008. You can use .NET reflector to examine the API. However, this is also unofficial, in that it is undocumented and thus could change without warning in service packs, etc.
Use the official C API. This is what I would recommend until an official managed wrapper class is released and documented. As noted above, the full API documentation has everything you need. I would recommend writing a simplified C wrapper dll around this API that does what you need and no more. Then, PInvoke your wrapper library.
Not able to test vdisk on my machine. But you can give a try to WMI queries.
eg. I can get the partition information using following code
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);
}
}
}
}
It gives pretty everything related to your machine. You can try the tool to get namespace and classes available on your machine : http://www.microsoft.com/downloads/details.aspx?familyid=2cc30a64-ea15-4661-8da4-55bbc145c30e&displaylang=en
Here are two solutions to retrieve virtual disks on the local machine and to print their information. The two solutions demonstrate how to use VDS COM objects to access these data both in a native and managed way.
I have create a partial COM Interop from the MSDN Documentation and from the Windows 7 SDK (mainly vds.h
). Note that the COM wrappers are partial, which means that some methods are yet to be ported.
Below is a managed application that uses the .NET COM interop to:
C:\Disk.vhd
).\\?\PhysicalDrive1
), its friendly name and other properties.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
}
}
Below is a native application that uses the VDS COM interfaces to:
C:\Disk.vhd
).\\?\PhysicalDrive1
), its friendly name and other properties.#include "initguid.h"
#include "vds.h"
#include <stdio.h>
#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);
}