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

发布于 2024-08-31 05:40:51 字数 812 浏览 8 评论 0原文

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

DISKPART> list vdisk

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

对我来说有趣的部分是文件名。如果我知道磁盘编号,我试图找到等效的函数,该函数可以为我提供文件名(在文件列下)。

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

我已经尝试过:

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

知道可能是什么功能吗?

When I list virtual disks within diskpart:

DISKPART> list vdisk

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

Interesting part for me here is file name. I tried to find equivalent of function that would give me file name (under File column) if I know disk number.

Ideally, I would give "\\?\PhysicalDrive2" and I would get "C:\Disk.vhd" as result.

I already tried:

  1. Using diskpart and parsing output - since it is undocumented format, it can change at any time. This is not something I would rely on.
  2. General VHD API - no function takes disk number as parameter.
  3. Microsoft.Storage.Vds.dll - There are enumerations that go through each drive (e.g. Service.Providers) but there is no property/function that will give me name of source file. While I can now be sure that e.g. drive D: is virtual drive, I still cannot know which .vhd file was attached.

Any idea which function that might be?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

沉溺在你眼里的海 2024-09-07 05:40:51

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

托管解决方案

我已经从 MSDN 文档 和来自创建了部分 COM 互操作Windows 7 SDK(主要是vds.h)。请注意,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 <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);
}

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.

Managed Solution

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:

  • Load the VDS service
  • Query for the Virtual Disk Providers
  • List all the Virtual Disk handled by each provider:
    • The virtual disk's properties gives its GUID, its full driver path, its volume size and its disk file (i.e. C:\Disk.vhd).
    • A virtual disk can be also be queried as a generic disk and gives its name (i.e. \\?\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
    }
}

Native Solution

Below is a native application that uses the VDS COM interfaces to:

  • Load the VDS service
  • Query for the Virtual Disk Providers
  • List all the Virtual Disk handled by each provider:
    • The virtual disk's properties gives its GUID, its full driver path, its volume size and its disk file (i.e. C:\Disk.vhd).
    • A virtual disk can be also be queried as a generic disk and gives its name (i.e. \\?\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);
}
背叛残局 2024-09-07 05:40:51

P/调用 GetStorageDependencyInformation 将提供严格的 VHD API 解决方案。虽然此函数不将驱动器号作为输入参数,但包装器方法会。包装器方法将驱动器号转换为“\\\\.\\PhysicalDriveN”形式的字符串,该字符串被传递到 CreateFile 并将生成的句柄传递到 <代码>获取存储依赖信息。类似的包装方法将接受单个 char 驱动器号的输入。
以下代码从 非托管示例

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
    }

}

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
    }

}
找回味觉 2024-09-07 05:40:51

虚拟磁盘 API 没有官方托管的 .NET 包装器。因此,您当前有三个选择:

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

  2. 使用Server 2008中添加的Microsoft.Storage.Vds.dll。您可以使用.NET 反射器来检查 API。然而,这也是非官方的,因为它没有文档记录,因此可能会在服务包等中毫无警告地进行更改。

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

There is no official managed .NET wrapper for the virtual disk APIs. So you currently have three options:

  1. Run the dos command and scrape the console response, which you don't want to do as it is not a stable API.

  2. 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.

  3. 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.

智商已欠费 2024-09-07 05:40:51

无法在我的计算机上测试虚拟磁盘。不过你可以尝试一下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=zh

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文