Получение имени файла виртуального диска с номера диска
Когда я перечисляю виртуальные диски внутри diskpart:
DISKPART> list vdisk
VDisk ### Disk ### State Type File
--------- -------- -------------------- --------- ----
VDisk 0 Disk 2 Attached not open Fixed C:\Disk.vhd
Интересная часть для меня здесь - имя файла. Я попытался найти эквивалент функции, которая дала бы мне имя файла (в столбце "Файл"), если я знаю номер диска.
В идеале я бы дал "\\? \ PhysicalDrive2" и в результате получил бы "C: \ Disk.vhd".
Я уже попробовал:
- Использование diskpart и парсинга вывода - поскольку это недокументированный формат, он может измениться в любое время. Это не то, на что я бы положился.
- Общий VHD API - ни одна функция не принимает номер диска в качестве параметра.
- Microsoft.Storage.Vds.dll - есть перечисления, которые проходят через каждый диск (например, Service.Providers), но нет свойства / функции, которая даст мне имя исходного файла. Хотя теперь я могу быть уверен, что, например, диск D: это виртуальный диск, я до сих пор не могу знать, какой файл.vhd был прикреплен.
Есть идеи, какая это может быть функция?
5 ответов
Вот два решения для извлечения виртуальных дисков на локальном компьютере и печати их информации. Два решения демонстрируют, как использовать объекты VDS COM для доступа к этим данным как в собственном, так и в управляемом виде.
Управляемое решение
Я создал частичное COM-взаимодействие из документации MSDN и из Windows 7 SDK (в основном vds.h
). Обратите внимание, что оболочки COM являются частичными, что означает, что некоторые методы еще не перенесены.
Ниже приводится управляемое приложение, которое использует взаимодействие.NET COM для:
- Загрузите сервис VDS
- Запрос к поставщикам виртуальных дисков
- Перечислите все виртуальные диски, обрабатываемые каждым провайдером:
- Свойства виртуального диска дают его GUID, полный путь к драйверу, размер тома и файл диска (т.е.
C:\Disk.vhd
). - Виртуальный диск также может быть запрошен как общий диск и дает его имя (т.е.
\\?\PhysicalDrive1
), его дружественное имя и другие свойства.
- Свойства виртуального диска дают его GUID, полный путь к драйверу, размер тома и файл диска (т.е.
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
}
}
Родное решение
Ниже приведено собственное приложение, которое использует интерфейсы COM VDS для:
- Загрузите сервис VDS
- Запрос к поставщикам виртуальных дисков
- Перечислите все виртуальные диски, обрабатываемые каждым провайдером:
- Свойства виртуального диска дают его GUID, полный путь к драйверу, размер тома и файл диска (т.е.
C:\Disk.vhd
). - Виртуальный диск также может быть запрошен как общий диск и дает его имя (т.е.
\\?\PhysicalDrive1
), его дружественное имя и другие свойства.
- Свойства виртуального диска дают его GUID, полный путь к драйверу, размер тома и файл диска (т.е.
#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);
}
P / Invoking GetStorageDependencyInformation обеспечит строго VHD API- решение. Хотя эта функция не принимает номер диска в качестве входного параметра, метод-обертка будет. Метод обертки преобразует номер диска в строку вида "\\\\. \\ PhysicalDriveN", которая передается в 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://stackru.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
}
}
Не существует официальной управляемой оболочки.NET для API виртуальных дисков. Итак, у вас есть три варианта:
Запустите команду dos и очистите ответ консоли, что не нужно делать, так как это не стабильный API.
использование
Microsoft.Storage.Vds.dll
это было добавлено в Server 2008. Вы можете использовать .NET рефлектор для проверки API. Однако это также является неофициальным, поскольку оно не имеет документов и, следовательно, может изменяться без предупреждения в пакетах обновления и т. Д.Используйте официальный C API. Это то, что я бы рекомендовал, пока не будет выпущен и задокументирован официальный управляемый класс-оболочка. Как отмечалось выше, полная документация по API содержит все, что вам нужно. Я бы порекомендовал написать упрощенную оболочку C для этого API, которая делает то, что вам нужно, и не более того. Затем, PInvoke вашей библиотеки оболочки.
Похоже, вам нужно использовать IEnumVdsObject, но я не уверен, какую ОС вы используете?
Не в состоянии проверить vdisk на моей машине. Но вы можете попробовать 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