Windows7虚拟盘(VHD)API

来源:互联网 发布:java 串口封装类 编辑:程序博客网 时间:2024/04/23 21:20

虚拟磁盘在 Windows 7 的 API 

http://msdn.microsoft.com/zh-cn/magazine/dd569754.aspx

The Virtual Disk API In Windows 7
Kenny Kerr

This article is based on a prerelease version of Windows 7. All information herein is subject to change.
The VHD Format 
Creating Virtual Disks 
Opening Virtual Disks 
Attaching Virtual Disks 
Querying Virtual Disks 
What's Next 
As I write this, the Windows 7 beta has been available for a few days, and I must say there is a lot to like. As usual, I took a look under the hood to see what is new in the Windows SDK. Windows 7 is very much a minor release as far as the SDK is concerned, and that's a good thing. The fundamentals of writing native C++ applications for Windows 7 have not changed much compared to the way they changed for Windows Vista. Having said that, however, Windows 7 has some completely new features that are sure to interest anyone looking to take advantage of the platform.
One of these features is the Virtual Disk API. Although designed with other formats in mind, the Virtual Disk API in the Windows 7 beta is very much geared toward the Microsoft Virtual Hard Disk (VHD) format popularized by virtualization products from Microsoft such as Hyper-V and Virtual PC.
This really takes me back because I've been involved with virtualization for quite a few years. When I first started working with virtualization technology almost ten years ago, VMware was the clear leader. Then in 2003 Microsoft acquired virtual machine technology from Connectix, and everything changed. All of a sudden there were two big players. It was clear the VHD format that Microsoft acquired from Connectix was well suited to the direction that Microsoft wanted to take with virtualization, namely to turn it into a platform. Whereas the VMware virtual disk formats were proprietary and very convoluted, often changing wildly from one release to the next, the VHD format was from the start straightforward and flexible enough to stand the test of time. In the intervening years, the VHD format has proven itself again and again, having been adopted by other products and technologies within Microsoft and by other software companies, big and small.
For this reason I'm happy to see that Windows 7 supports the VHD format natively.This means that users and administrators can easily create and attach virtual disks as if they were additional physical storage devices, without installing any third-party drivers or tools. You can, for example, use the Disk Management MMC (Microsoft Management Console) snap-in or the DISKPART command-line tool to create and attach virtual disks. You can then partition, format, and use them like any other hard disk on your computer.
In addition, you also gain very granular control over the creation and management of virtual disks. At the heart of these capabilities is VirtDisk.dll, which provides a low-level C API, known as the Virtual Disk API, for creating and manipulating virtual disks. This API provides access to a number of kernel-mode drivers that are needed to actually represent the disk and its volumes in the storage subsystem so that file system drivers can be layered on top without requiring any knowledge of the actual source of the storage.
Disk management tools typically interact with virtual disks via the Virtual Disk Service (VDS) that itself relies on the Virtual Disk API for handling VHD-based storage. Of course Hyper-V has its own Windows Management Instrumentation (WMI)–based API for creating and manipulating virtual machines, and it too relies on the Virtual Disk API.
Before I dive in and show how you can use the Virtual Disk API, I'll quickly describe the basics of the VHD format. You'll see that given this new API, you can now throw away much of the code you needed previously for managing virtual disks.

The VHD Format
The VHD format provides three different image types: fixed, dynamic, and differencing disks. All three disk types include a 512-byte VHD footer residing at the end of the disk file. More on this in a minute.
Fixed disks are the simplest type and provide the best performance because the disk file is fully allocated to accommodate the size requested when the disks are created. A 500-MB fixed disk will be exactly 500 x 1024 x 1024 + 512 bytes in size. Because the footer is at the end of the disk, the disk's storage can align with the beginning of the file to ensure the simplest and fastest possible random access.
Dynamic disks are called sparse disks by the Virtual Disk API, and sparse is a good way to think of them. The disk files are initially created with just enough space to store the VHD footer as well as some additional metadata that is needed to manage the dynamic nature of the storage allocation. As data is written to the disk, additional blocks of storage are allocated at the end of the disk file. Dynamic disks are advantageous because they take up far less space if not used at full capacity, which is the case most of the time. The disadvantage is that the additional indirection and metadata management required to read, write, and grow a dynamic disk on demand takes its toll on performance. For this reason, dynamic disks are favored in testing scenarios, whereas fixed disks are preferred in production scenarios because performance is a high priority.
Differencing disks are very similar to dynamic disks internally, but other characteristics are very different. As with dynamic disks, differencing disks use dynamically allocated blocks, but those blocks contain only modifications related to a parent disk. This type of disk is therefore dependent on a parent disk to function. The parent of a differencing disk can be either a fixed or a dynamic disk. The parent can, in fact, be another differencing disk, allowing a chain or tree of disks to be created. Disks that represent leaf nodes can be freely written to, but nonleaf nodes should be considered read-only because any descendant differencing disks rely on them to fill in the blanks, so to speak, and if they were to change it would very likely result in corrupt virtual disks.
As I mentioned earlier, the different types of disks share a common footer. This footer contains information such as the logical size of the disk, disk geometry, the type of disk, the disk's globally unique identifier, and so on. For dynamic and differencing disks the footer also includes an offset value indicating where the dynamic header resides relative to the beginning of a disk. This secondary structure chiefly contains information that might be required to locate and identify a parent disk, if necessary, as well as another offset indicating where the disk's block allocation table (BAT) resides.This table indicates which blocks have been allocated as well as their absolute offsets in the disk file.
With that introduction out of the way, let's dive in and take a look at the Virtual Disk API.
Keep in mind that the API is designed to allow Microsoft to add support for additional formats in the future. In fact, support for the ISO optical disk image format has been considered but has not been added as of the Windows 7 beta. I hope that the necessary virtual disk support provider will be included in the release build. This would allow users to attach and mount ISO images as read-only hard drives.

Creating Virtual Disks
Virtual disks are represented by opaque handles, much like other system objects such as files, registry keys, and so on. The familiar CloseHandle function is even used to close a virtual disk handle. The Active Template Library's (ATL) CHandle class is a good choice for managing this resource. You can derive a "VirtualDisk" class from CHandle to wrap up some of the boilerplate code necessary to manipulate virtual disks.
Whenever you open or create a virtual disk, you need to specify the disk's storage type.This is accomplished with the VIRTUAL_STORAGE_TYPE structure. Storage types are defined for the ISO and VHD formats. The structure also specifies the vendor that provides the implementation for the particular storage type. Here's how you can identify the VHD storage type:
VIRTUAL_STORAGE_TYPE storageType ={    VIRTUAL_STORAGE_TYPE_DEVICE_VHD,    VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT};
The CreateVirtualDisk function creates all three types of virtual disks. Along with the storage type, you must populate a CREATE_VIRTUAL_DISK_PARAMETERS structure.How this structure is populated depends on the type of virtual disk you would like to create. Many of the Virtual Disk API structures use a versioning scheme to accommodate future updates to the API. The structures begin with a member named Version followed by a union of structures. For example, here's how you can populate the common fields for creating virtual disks:
CREATE_VIRTUAL_DISK_PARAMETERS parameters ={    CREATE_VIRTUAL_DISK_VERSION_1};parameters.Version1.MaximumSize = size;parameters.Version1.BlockSizeInBytes = CREATE_VIRTUAL_DISK_PARAMETERS_DEFAULT_BLOCK_SIZE;parameters.Version1.SectorSizeInBytes = CREATE_VIRTUAL_DISK_PARAMETERS_DEFAULT_SECTOR_SIZE;
The size of the virtual disk is specified in bytes and must be a multiple of 512. The block size and sector size is configurable, but if you need to ensure the greatest level of compatibility across implementations the default values are a good choice. The Version1 structure also provides a UniqueId member, but if you leave this zeroed out, the CreateVirtualDisk function will generate a GUID for you. The SourcePath member may also be specified for all disk types except the differencing disks. This instructs CreateVirtualDisk to copy the contents of the source disk into the newly created virtual disk. The two do not need to be of the same type. In fact, the source disk does not even have to be a virtual disk and can be a physical disk that you would like to make a copy of.
Figure 1 provides the beginnings of a VirtualDisk wrapper class that includes a CreateFixed member function for creating fixed virtual disks. Note that for fixed disks you must specify the CREATE_VIRTUAL_DISK_FLAG_FULL_PHYSICAL_ALLOCATION flag. Creating a dynamic disk is exactly the same as creating a fixed disk except that you must omit this flag and can specify the CREATE_VIRTUAL_DISK_FLAG_NONE flag instead. Creating a differencing disk is also much the same. The difference there is that you must not set the size, as it is inferred from the parent disk, and you must specify the parent with the ParentPath member of the Version1 structure. The SourcePath cannot be set for differencing disks for obvious reasons.
class VirtualDisk : public CHandle{public:    DWORD CreateFixed(PCWSTR path,                      ULONGLONG size,                      VIRTUAL_DISK_ACCESS_MASK accessMask,                      __in_opt PCWSTR source,                      __in_opt PSECURITY_DESCRIPTOR securityDescriptor,                      __in_opt OVERLAPPED* overlapped)    {        ASSERT(0 == m_h);        ASSERT(0 != path);        ASSERT(0 == size % 512);        VIRTUAL_STORAGE_TYPE storageType =        {            VIRTUAL_STORAGE_TYPE_DEVICE_VHD,            VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT        };        CREATE_VIRTUAL_DISK_PARAMETERS parameters =        {            CREATE_VIRTUAL_DISK_VERSION_1        };        parameters.Version1.MaximumSize = size;        parameters.Version1.BlockSizeInBytes = CREATE_VIRTUAL_DISK_        PARAMETERS_DEFAULT_BLOCK_SIZE;        parameters.Version1.SectorSizeInBytes = CREATE_VIRTUAL_DISK_        PARAMETERS_DEFAULT_SECTOR_SIZE;        parameters.Version1.SourcePath = source;        return ::CreateVirtualDisk(&storageType,                                   path,                                   accessMask,                                   securityDescriptor,                                   CREATE_VIRTUAL_DISK_FLAG_FULL_                                   PHYSICAL_ALLOCATION,                                   0, // no provider-specific flags                                   &parameters,                                   overlapped,                                   &m_h);    } 
The CreateVirtualDisk function provides a few additional parameters that are worth mentioning. The VIRTUAL_DISK_ACCESS_MASK enumeration provides a set of flags for controlling the access that the API will grant callers through the resulting handle.Although you can specify VIRTUAL_DISK_ACCESS_ALL, this is often undesirable as it prevents you from running certain operations such as querying a virtual disk that is currently attached as a storage device. The other very useful feature is the ability to specify an OVERLAPPED structure. This is supported by a number of the Virtual Disk API functions, and as you would expect has the effect of performing the operation asynchronously. Simply provide a manual reset event and it will be signaled upon completion.

Opening Virtual Disks
The OpenVirtualDisk function can be used to open a virtual disk. As with virtual disk creation, you must provide a VIRTUAL_STORAGE_TYPE structure to identify the storage type. An OPEN_VIRTUAL_DISK_PARAMETERS structure may optionally be provided but is typically only required when manipulating differencing disk relationships.
Figure 2 provides an Open member function to add to the VirtualDisk wrapper class started in Figure 1Opening virtual disks is typically simpler than creating them, but some of the flags and options must be used in a very particular way to allow certain maintenance operations such as merging and attaching virtual disks.
DWORD Open(PCWSTR path,           VIRTUAL_DISK_ACCESS_MASK accessMask,           OPEN_VIRTUAL_DISK_FLAG flags, // OPEN_VIRTUAL_DISK_FLAG_NONE           ULONG readWriteDepth) // OPEN_VIRTUAL_DISK_RW_DEPTH_DEFAULT{    ASSERT(0 == m_h);    ASSERT(0 != path);    VIRTUAL_STORAGE_TYPE storageType =    {        VIRTUAL_STORAGE_TYPE_DEVICE_VHD,        VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT    };    OPEN_VIRTUAL_DISK_PARAMETERS parameters =    {        OPEN_VIRTUAL_DISK_VERSION_1    };    parameters.Version1.RWDepth = readWriteDepth;    return ::OpenVirtualDisk(&storageType,                             path,                             accessMask,                             flags,                             &parameters,                             &m_h);}

Attaching Virtual Disks
The Windows 7 beta uses the term surface, or surfacing, to mean attaching the disk as a storage device in the operating system. This has subsequently been changed to the more obvious word attach. The AttachVirtualDisk (called SurfaceVirtualDisk in the beta) function attaches the virtual disk. The virtual disk is identified by a handle previously obtained from a call to either CreateVirtualDisk or OpenVirtualDisk. You must make sure that the handle has the appropriate access defined for it. To attach and detach a virtual disk, you must also have the SE_MANAGE_VOLUME_NAME privilege present in your token. This privilege is stripped from an administrator's token when User Account Control is in use, so you may need to elevate your application to gain access to the unrestricted token that includes this privilege.
Figure 3 provides an Attach member function to add to the VirtualDisk wrapper class.The ATTACH_VIRTUAL_DISK_FLAG (called SURFACE_VIRTUAL_DISK_FLAG in the beta) parameter is how you control the method in which the virtual disk is attached.
DWORD Attach(ATTACH_VIRTUAL_DISK_FLAG flags,              __in_opt PSECURITY_DESCRIPTOR securityDescriptor,              __in_opt OVERLAPPED* overlapped){    ASSERT(0 != m_h);    return ::AttachVirtualDisk(m_h,                                securityDescriptor,                                flags,                                0, // no provider-specific flags                                0, // no parameters                                overlapped);}
ATTACH_VIRTUAL_DISK_FLAG_READ_ONLY (called SURFACE_VIRTUAL_DISK_FLAG_READ_ONLY in the beta) can be specified to ensure that the attached disk is write-protected. This cannot be overridden by an attempt to make the disk writable with VDS.
ATTACH_VIRTUAL_DISK_FLAG_NO_DRIVE_LETTER (called SURFACE_VIRTUAL_DISK_FLAG_NO_DRIVE_LETTER in the beta) will prevent Windows from automatically assigning drive letters to any volumes present in the virtual disk.You are free then to mount any volumes programmatically or not at all, depending on your needs. The GetVirtualDiskPhysicalPath function can be used to identify the physical path where the virtual disk was attached.
ATTACH_VIRTUAL_DISK_FLAG_PERMANENT_LIFETIME (called SURFACE_VIRTUAL_DISK_FLAG_PERMANENT_LIFETIME in the beta) ensures that the virtual disk remains attached even after the virtual disk handle is closed. Failure to specify this flag results in the virtual disk being detached automatically when the handle is closed. To detach the virtual disk in this case, you need to call the DetachVirtualDisk function (called UnsurfaceVirtualDisk in the beta).

Querying Virtual Disks
The GetVirtualDiskInformation function allows you to query a virtual disk for different classes of information. The information is communicated using the GET_VIRTUAL_DISK_INFO structure, which uses the same version pattern used by many of the other Virtual Disk API structures. For example, to get the disk's size information you set the structure's version to GET_VIRTUAL_DISK_INFO_SIZE. The corresponding Size union member will then be populated. Figure 4 illustrates this.
DWORD GetSize(__out ULONGLONG& virtualSize,              __out ULONGLONG& physicalSize,              __out ULONG& blockSize,              __out ULONG& sectorSize) const{    ASSERT(0 != m_h);    GET_VIRTUAL_DISK_INFO info =    {        GET_VIRTUAL_DISK_INFO_SIZE    };    ULONG size = sizeof(GET_VIRTUAL_DISK_INFO);    const DWORD result = ::GetVirtualDiskInformation(m_h,                                                     &size,                                                     &info,                                                     0); // fixed size    if (ERROR_SUCCESS == result)    {        virtualSize = info.Size.VirtualSize;        physicalSize = info.Size.PhysicalSize;        blockSize = info.Size.BlockSize;        sectorSize = info.Size.SectorSize;    }    return result;} 
The GetVirtualDiskInformation function operates on a virtual disk handle, so again you need to ensure you have the appropriate access. In this case the VIRTUAL_DISK_ACCESS_GET_INFO permission is required. Since some of the information that can be obtained using GetVirtualDiskInformation is variable in length, it provides two additional parameters to specify both how much storage is initially being provided and how much was ultimately populated. For most of the information you will query the size is known ahead of time and the last parameter can be omitted, as is the case in Figure 4.
The notable exception is when querying a differencing disk for the location, or path, of a parent virtual disk. In this case you need to start by determining the amount of memory that is required with an initial call to GetVirtualDiskInformation. This call will fail with ERROR_INSUFFICIENT_BUFFER but provide you with the size of the buffer that needs to be allocated. You can then call the function a second time to actually get the information. The GET_VIRTUAL_DISK_INFO_PARENT_LOCATION version flag is used to get the parent location. It is, however, a little more complicated still. Since maintaining a reference to a parent is so critical for the operation of a differencing disk, the VHD format provides a degree of redundancy that can be exploited should the link to the parent be broken. Suffice it to say that the querying for the parent location involves parsing a sequence of null-terminated strings, terminated by an empty string. This is the same as the REG_MULTI_SZ registry value type. Figure 5 shows you how it's done.The example uses ATL's CAtlArray collection class as well ATL's CString class.
DWORD GetParentLocation(__out bool& resolved,                        __out CAtlArray<CString>& paths) const{    ASSERT(0 != m_h);    GET_VIRTUAL_DISK_INFO info =    {        GET_VIRTUAL_DISK_INFO_PARENT_LOCATION    };    ULONG size = sizeof(GET_VIRTUAL_DISK_INFO);    DWORD result = ::GetVirtualDiskInformation(m_h,                                               &size,                                               &info,                                               0); // not used    if (ERROR_INSUFFICIENT_BUFFER != result)    {        return result;    }    CAtlArray<BYTE> buffer;    if (!buffer.SetCount(size))    {        return ERROR_NOT_ENOUGH_MEMORY;    }    GET_VIRTUAL_DISK_INFO* pInfo = reinterpret_cast<GET_VIRTUAL_DISK_    INFO*>(buffer.GetData());    pInfo->Version = GET_VIRTUAL_DISK_INFO_PARENT_LOCATION;    result = ::GetVirtualDiskInformation(m_h,                                         &size,                                         pInfo,                                         0); // not used    if (ERROR_SUCCESS == result)    {        resolved = 0 != pInfo->ParentLocation.ParentResolved;        PCWSTR path = pInfo->ParentLocation.ParentLocationBuffer;        while (0 != *path)        {            paths.Add(path);            path += paths[paths.GetCount() - 1].GetLength() + 1;        }    }    return result;}

What's Next
The Virtual Disk API provides a few more functions primarily aimed at maintaining or repairing virtual disks. The MergeVirtualDisk function allows you to merge any changes in a differencing disk back into a parent disk. It supports merging with any parent in the chain. Functions are also provided for compacting and expanding virtual disks as well as updating relational metadata in the case of differencing disks.
Note that the Windows SDK for the Windows 7 beta omitted the VirtDisk.lib file necessary to link to the Virtual Disk API functions. This will be corrected for the release.Developers using the beta can use the LoadLibrary and GetProcAddress functions to load and address the functions or generate the lib file yourself.

Send your questions and comments to mmwincpp@microsoft.com

Kenny Kerr is a software craftsman specializing in software development for Windows. He has a passion for writing and teaching developers about programming and software design. You can reach Kenny at weblogs.asp.net/kennykerr .
虚拟磁盘在 Windows 7 的 API
Kenny Kerr

这篇文章基于 Windows 7 的预发布版本。 如更改,恕本文档所提及的所有信息。
VHD 格式 
创建虚拟磁盘 
打开虚拟磁盘 
附加虚拟磁盘 
查询虚拟磁盘 
下一个 
我撰写本文,Windows 7 Beta 已几个的天内可用,并且我必须说没有要像很多。 同往常一样,我时间以查看 Windows SDK 中的新究查看。 Windows 7 是非常一个次要版本就而言,SDK,而且的一件好事。 编写 Windows 7 本机 C++ 应用程序的基础知识没有改动得与它们更改为 Windows Vista 的方式。 具有所说的但是,Windows 7 包含一些全新功能,确信利息任何人都希望利用该平台。
这些功能之一是虚拟磁盘 API。 虽然设计考虑其他格式,但虚拟磁盘 API 在 Windows 7 测试版中的是非常针对 Microsoft 虚拟硬盘 (VHD) 格式,如超 V 和 Virtual PC 的虚拟化产品 Microsoft popularized。
真正转我由于我已经涉及相当多年的虚拟化。 当我首次启动使用虚拟化技术几乎十年前时,VMware 将是清除的前导符。 然后在 2003 Microsoft 收购 Connectix,虚拟机技术,并且所有更改。 所有的一个突然没有两个大的播放机。 它是清除 Microsoft 收购从 Connectix VHD 格式是适合的 Microsoft 希望即执行虚拟化,方向变成一个平台。 而 VMware 虚拟磁盘格式已专用和非常 convoluted,通常从版本更改 wildly 为下,VHD 格式将是时间的从一开始简单和灵活以突出显示测试。 在中间的年中具有已采用其他产品和 Microsoft 的技术和其他软件公司大和小型,以后反复本身已证明 VHD 格式。
因此我高兴看到 Windows 7 本机支持 VHD 格式。 这意味着用户和管理员可以轻松地创建和附加虚拟磁盘,而不安装所有第三方驱动程序或工具的其他物理存储设备一样。可以,创建并附加虚拟磁盘是例如使用磁盘管理 MMC (Microsoft 管理控制台) 管理单元或 DISKPART 命令行工具。 您可以然后分区,格式化,并使用其像任何其他硬盘上您的计算机上。
此外,还获得非常精确控制创建和管理虚拟磁盘。 这些功能的核心提供一个低级的 C API 的 VirtDisk.dll 称为虚拟磁盘 API,创建和操作虚拟磁盘。 此 API 提供对许多这样的文件系统驱动程序可以在最前面分而无需实际源存储的任何知识实际上代表磁盘和存储子系统中的卷所需的内核模式驱动程序的访问。
磁盘管理工具通常与通过虚拟磁盘服务 (VDS) 本身依赖虚拟磁盘 API 用于处理 VHD 基于存储的虚拟磁盘的交互。 当然超 V 有它自己的 Windows Management Instrumentation (WMI) 基于的 API 创建和操作虚拟机并它太依赖虚拟磁盘 API。
我在研究,并显示了如何使用虚拟磁盘 API 之前,我将快速介绍 VHD 格式的基础知识。 您将看到指定此新的 API,您可以立即丢弃多您以前需要用于管理虚拟磁盘的代码。

VHD 格式
VHD 格式提供三种不同的图像类型: 修复,动态,和不同的磁盘。 所有三个磁盘类型包括 512 字节 VHD 页脚位于磁盘文件的末尾。 多对此在一分钟的时间。
固定的磁盘是简单类型,并提供最佳性能,因为磁盘文件被完全分配以适应请求创建磁盘时的大小。 500 MB 的固定的磁盘将为完全 500 x 1024 x 1024 按 512 字节的大小。 磁盘结尾处页脚是,磁盘的存储空间可以对齐以确保最简单和最快可能随机访问文件的开头。
动态磁盘称作稀疏磁盘的虚拟磁盘 API,稀疏是让我们一个好办法。 只需足够空间来存储 VHD 页脚以及管理存储分配的动态性质所需的一些其他元数据最初创建该磁盘文件。 数据写入到磁盘中,其他块的存储空间分配磁盘文件的末尾。 动态磁盘是有利的因为它们占用少得多的空间如果不使用在完全是这样大部分时间的容量。 缺点是额外的间接寻址和元数据读取,所需的管理编写,增长对性能的收费的请求将在动态磁盘。为此动态磁盘被号在测试方案,而固定的磁盘首选生产方案中 (因为性能是高的优先级。
不同的磁盘非常类似于动态磁盘内部,但其他特征是很大差异。 与动态的磁盘差分磁盘使用动态分配块,,但这些块包含与父磁盘的唯一修改。 因此,此类磁盘的才依赖于函数的父磁盘。 不同的父项可以是磁盘的一个固定或动态磁盘。 父可以实际上,是另一个不同的磁盘允许一个链或磁盘才能创建的树。 表示叶节点的磁盘可以自由地写入,但是非叶节点因为任何后代的不同磁盘依赖于他们填写空白,这样说应被视为只读的并且它们进行更改将很有可能会导致损坏的虚拟磁盘。
如我之前提到的不同类型的磁盘共享一个公共的页脚。 该页脚包含磁盘、 磁盘几何、 的磁盘类型、 磁盘的全局唯一标识符和等等逻辑大小等信息。 对于动态和不同的磁盘页脚还指示动态的标题相对于磁盘的起点所驻留的偏移的值。 此辅助结构 chiefly 包含可能需要查找并确定将父磁盘,如有必要,以及指示磁盘的块分配表 (BAT) 所在的另一个偏移量的信息。 此表列出的块已分配,以及磁盘文件中其绝对偏移量。
与不该简介,让我们研究中,看一看虚拟磁盘 API。
请记住 API 为了使 Microsoft 能够在以后添加对其他格式的支持。 实际上,支持 ISO 光盘映像格式被视为但尚未添加的 Windows 7 试用版。 我希望将包含所需的虚拟磁盘支持提供商发行版本中。 这将允许用户附加和装入 ISO 映像为只读的硬盘驱动器。

创建虚拟磁盘
虚拟磁盘由表示不透明的句柄与其他系统一样很多对象如文件、 注册表项和等等。 熟悉的 CloseHandle 函数甚至用于关闭虚拟磁盘句柄。 在活动模板库的 (ATL) 无论是 CHandle 类是一个非常好的管理此资源选择。 您可以在从总结的一些样本代码需要处理虚拟磁盘的 CHandle 派生"VirtualDisk 类。
每当您打开或创建一个虚拟磁盘时, 需要指定磁盘的存储类型。 这完成 VIRTUAL_STORAGE_TYPE 结构。 为 ISO 和 VHD 格式定义存储类型。 结构还指定供应商提供为特定存储类型实现的。 下面是如何可以识别 VHD 存储类型:
VIRTUAL_STORAGE_TYPE storageType ={    VIRTUAL_STORAGE_TYPE_DEVICE_VHD,    VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT};
CreateVirtualDisk 函数创建了所有三种类型的虚拟磁盘。 以及与存储类型中,您必须填充 CREATE_VIRTUAL_DISK_PARAMETERS 结构。 如何填充该结构取决于要创建的虚拟磁盘的类型。 许多虚拟磁盘 API 结构以容纳将来的更新到 API 使用版本控制方案。 结构开头成员名为跟结构的并集的版本。 例如,下面是如何可以填充公共字段来创建虚拟磁盘:
CREATE_VIRTUAL_DISK_PARAMETERS parameters ={    CREATE_VIRTUAL_DISK_VERSION_1};parameters.Version1.MaximumSize = size;parameters.Version1.BlockSizeInBytes = CREATE_VIRTUAL_DISK_PARAMETERS_DEFAULT_BLOCK_SIZE;parameters.Version1.SectorSizeInBytes = CREATE_VIRTUAL_DISK_PARAMETERS_DEFAULT_SECTOR_SIZE;
虚拟磁盘的大小均指定以字节为单位),且必须是 512 的倍数。 块大小和扇区大小为配置,但如果您要确保在实现的兼容性的最大级别默认值的一个很好的选择。 Version1 结构还提供了一个 UniqueId 成员,但如果将此清,CreateVirtualDisk 函数将生成的 GUID。 SourcePath 成员还指定所有的磁盘类型不同的磁盘除外。 这将指示 CreateVirtualDisk 源磁盘的内容复制到新创建的虚拟磁盘。 两个不需要为同一类型。实际上,源磁盘甚至不必是虚拟的磁盘,,可以是要创建的副本的物理磁盘。
图 1 提供了 VirtualDisk 包装类,包括用于创建固定虚拟磁盘 CreateFixed 成员函数的 beginnings。 请注意对于固定磁盘您必须指定 CREATE_VIRTUAL_DISK_FLAG_FULL_PHYSICAL_ALLOCATION 标志。 创建动态磁盘是完全相同与创建固定的磁盘不同,,您必须忽略此标志,并可以指定 CREATE_VIRTUAL_DISK_FLAG_NONE 标志的。 创建一个不同的磁盘与还得多。 没有必须将未设置该的大小为其区别推断从在父磁盘,因此您必须在与 ParentPath 成员 Version1 结构的指定父。 在 SourcePath 不能设置为差分明显的原因的磁盘。
class VirtualDisk : public CHandle{public:    DWORD CreateFixed(PCWSTR path,                      ULONGLONG size,                      VIRTUAL_DISK_ACCESS_MASK accessMask,                      __in_opt PCWSTR source,                      __in_opt PSECURITY_DESCRIPTOR securityDescriptor,                      __in_opt OVERLAPPED* overlapped)    {        ASSERT(0 == m_h);        ASSERT(0 != path);        ASSERT(0 == size % 512);        VIRTUAL_STORAGE_TYPE storageType =        {            VIRTUAL_STORAGE_TYPE_DEVICE_VHD,            VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT        };        CREATE_VIRTUAL_DISK_PARAMETERS parameters =        {            CREATE_VIRTUAL_DISK_VERSION_1        };        parameters.Version1.MaximumSize = size;        parameters.Version1.BlockSizeInBytes = CREATE_VIRTUAL_DISK_        PARAMETERS_DEFAULT_BLOCK_SIZE;        parameters.Version1.SectorSizeInBytes = CREATE_VIRTUAL_DISK_        PARAMETERS_DEFAULT_SECTOR_SIZE;        parameters.Version1.SourcePath = source;        return ::CreateVirtualDisk(&storageType,                                   path,                                   accessMask,                                   securityDescriptor,                                   CREATE_VIRTUAL_DISK_FLAG_FULL_                                   PHYSICAL_ALLOCATION,                                   0, // no provider-specific flags                                   &parameters,                                   overlapped,                                   &m_h);    } 
CreateVirtualDisk 函数提供了几个值得一提的其他参数。VIRTUAL_DISK_ACCESS_MASK 枚举提供了用于控制 API 将授予通过得到的句柄的调用方的访问的标记的一组。 虽然可以指定 VIRTUAL_DISK_ACCESS_ALL,这是通常不需要它阻止您运行某些操作如查询当前附加为存储设备的虚拟磁盘。 其他非常有用的功能是能够指定一个 OVERLAPPED 结构。 这支持多种在虚拟磁盘 API 函数,正常将具有异步执行该操作的效果。 只需提供手动重置事件,并将被终止完成。

打开虚拟磁盘
OpenVirtualDisk 函数可打开虚拟的磁盘。 为使用虚拟磁盘创建,您必须提供一个 VIRTUAL_STORAGE_TYPE 结构,以标识存储类型。OPEN_VIRTUAL_DISK_PARAMETERS 结构可能会选择提供,但通常是只需要时操作不同的磁盘关系。
图 2 提供了一个打开的成员函数,以将添加到 图 1 中启动 VirtualDisk 包装类。 打开虚拟磁盘是通常比创建,更简单而的一些标志和选项必须在使用允许某些维护操作 (如合并和附加虚拟磁盘以非常特定的方式。
DWORD Open(PCWSTR path,           VIRTUAL_DISK_ACCESS_MASK accessMask,           OPEN_VIRTUAL_DISK_FLAG flags, // OPEN_VIRTUAL_DISK_FLAG_NONE           ULONG readWriteDepth) // OPEN_VIRTUAL_DISK_RW_DEPTH_DEFAULT{    ASSERT(0 == m_h);    ASSERT(0 != path);    VIRTUAL_STORAGE_TYPE storageType =    {        VIRTUAL_STORAGE_TYPE_DEVICE_VHD,        VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT    };    OPEN_VIRTUAL_DISK_PARAMETERS parameters =    {        OPEN_VIRTUAL_DISK_VERSION_1    };    parameters.Version1.RWDepth = readWriteDepth;    return ::OpenVirtualDisk(&storageType,                             path,                             accessMask,                             flags,                             &parameters,                             &m_h);}

附加虚拟磁盘
Windows 7 Beta 来表示附加磁盘为操作系统中的存储设备使用术语表面,或 surfacing。 这以后已更改为更明显的单词附加。 AttachVirtualDisk (在该测试版中称为 SurfaceVirtualDisk) 函数将附加虚拟磁盘。 虚拟磁盘由以前从调用 CreateVirtualDisk 或 OpenVirtualDisk 获取句柄标识。 您必须确保句柄具有为它定义适当的访问。 要附加和分离虚拟的磁盘,也必须位于您的令牌 SE_MANAGE_VOLUME_NAME 权限。 此权限是从管理员的令牌时,会中去除用户帐户控制正在使用,因此您可能需要提升应用程序能够访问包括此特权的不受限令牌。
图 3 提供了将添加到 VirtualDisk 包装类的附加成员函数。ATTACH_VIRTUAL_DISK_FLAG (在该测试版中称为 SURFACE_VIRTUAL_DISK_FLAG) 参数是控制在其中连接虚拟磁盘,方法的方式。
DWORD Attach(ATTACH_VIRTUAL_DISK_FLAG flags,              __in_opt PSECURITY_DESCRIPTOR securityDescriptor,              __in_opt OVERLAPPED* overlapped){    ASSERT(0 != m_h);    return ::AttachVirtualDisk(m_h,                                securityDescriptor,                                flags,                                0, // no provider-specific flags                                0, // no parameters                                overlapped);}
ATTACH_VIRTUAL_DISK_FLAG_READ_ONLY (在该测试版中称为 SURFACE_VIRTUAL_DISK_FLAG_READ_ONLY) 可以指定以确保附加的磁盘写保护。 这不能被试图进行磁盘写与 VDS 重写。
ATTACH_VIRTUAL_DISK_FLAG_NO_DRIVE_LETTER (在该测试版中称为 SURFACE_VIRTUAL_DISK_FLAG_NO_DRIVE_LETTER) 将阻止 Windows 自动虚拟磁盘中的任何卷分配驱动器号。 您可以自由然后装入任何卷以编程方式或根本不根据您的需要。 GetVirtualDiskPhysicalPath 函数用于确定物理路径已在连接虚拟磁盘。
ATTACH_VIRTUAL_DISK_FLAG_PERMANENT_LIFETIME (在该测试版中称为 SURFACE_VIRTUAL_DISK_FLAG_PERMANENT_LIFETIME) 可确保即使关闭虚拟磁盘句柄后,虚拟磁盘保持连接。 若要指定此标志的失败导致被分离自动关闭句柄时,虚拟磁盘。 要在这种情况下取消虚拟磁盘,必须调用 DetachVirtualDisk 函数 (在该测试版中称为 UnsurfaceVirtualDisk)。

查询虚拟磁盘
GetVirtualDiskInformation 函数允许您查询的信息的其他类的虚拟磁盘。 该信息被传递使用 GET_VIRTUAL_DISK_INFO 结构使用相同版本模式由许多其他虚拟磁盘 API 结构。是例如若要获取磁盘的大小信息设置到 GET_VIRTUAL_DISK_INFO_SIZE 结构的版本。 然后将填充相应的大小联合成员。 图 4 说明了这一点。
DWORD GetSize(__out ULONGLONG& virtualSize,              __out ULONGLONG& physicalSize,              __out ULONG& blockSize,              __out ULONG& sectorSize) const{    ASSERT(0 != m_h);    GET_VIRTUAL_DISK_INFO info =    {        GET_VIRTUAL_DISK_INFO_SIZE    };    ULONG size = sizeof(GET_VIRTUAL_DISK_INFO);    const DWORD result = ::GetVirtualDiskInformation(m_h,                                                     &size,                                                     &info,                                                     0); // fixed size    if (ERROR_SUCCESS == result)    {        virtualSize = info.Size.VirtualSize;        physicalSize = info.Size.PhysicalSize;        blockSize = info.Size.BlockSize;        sectorSize = info.Size.SectorSize;    }    return result;} 
函数作用于虚拟磁盘句柄在 GetVirtualDiskInformation,因此再次需要确保您具有适当的访问权限。 在这种情况下 VIRTUAL_DISK_ACCESS_GET_INFO 权限是必需的。 因为某些使用 GetVirtualDiskInformation 可以获得的信息是可变长度它提供两个指定最初所提供多少存储和填充量时的最终状态的其他参数。 大部分信息会查询大小已知之前的时间,而最后一个参数可以忽略, 图 4 中那样。
值得注意例外情况是查询不同的磁盘位置,或的父虚拟磁盘的路径时。 在这种情况下您需要首先确定 GetVirtualDiskInformation 的初始调用所需的内存量。 此调用将失败,出现 ERROR _ INSUFFICIENT _ BUFFER,但您提供需要分配的缓冲区的大小。 您可以然后调用该函数第二次实际获得信息。 GET_VIRTUAL_DISK_INFO_PARENT_LOCATION 版本标记用于获取父位置。 但是,它是稍微复杂一些仍。 由于维护对父引用是那么重要,为不同的磁盘的操作的 VHD 格式提供一定程度的冗余可以被利用的父链接应断开。 可以地说,该查询的父位置需要分析的终止空字符串的空终止字符串序列。 这是为 REG _ MULTI _ SZ 注册表值类型相同的。 图 5 显示的方式。 示例使用 ATL CAtlArray 集合以及类 ATL 的 CString 类。
DWORD GetParentLocation(__out bool& resolved,                        __out CAtlArray<CString>& paths) const{    ASSERT(0 != m_h);    GET_VIRTUAL_DISK_INFO info =    {        GET_VIRTUAL_DISK_INFO_PARENT_LOCATION    };    ULONG size = sizeof(GET_VIRTUAL_DISK_INFO);    DWORD result = ::GetVirtualDiskInformation(m_h,                                               &size,                                               &info,                                               0); // not used    if (ERROR_INSUFFICIENT_BUFFER != result)    {        return result;    }    CAtlArray<BYTE> buffer;    if (!buffer.SetCount(size))    {        return ERROR_NOT_ENOUGH_MEMORY;    }    GET_VIRTUAL_DISK_INFO* pInfo = reinterpret_cast<GET_VIRTUAL_DISK_    INFO*>(buffer.GetData());    pInfo->Version = GET_VIRTUAL_DISK_INFO_PARENT_LOCATION;    result = ::GetVirtualDiskInformation(m_h,                                         &size,                                         pInfo,                                         0); // not used    if (ERROR_SUCCESS == result)    {        resolved = 0 != pInfo->ParentLocation.ParentResolved;        PCWSTR path = pInfo->ParentLocation.ParentLocationBuffer;        while (0 != *path)        {            paths.Add(path);            path += paths[paths.GetCount() - 1].GetLength() + 1;        }    }    return result;}

下一个
虚拟磁盘 API 提供了几个更多的功能主要针对维护或修复虚拟磁盘。 MergeVirtualDisk 函数允许您不同的磁盘中的任何更改合并回到父磁盘。 它支持与链中的任何父合并。功能还提供用于压缩和展开虚拟磁盘以及正在更新关系的元数据差分磁盘的情况。
请注意 Windows SDK for Windows 7 Beta 省略 VirtDisk.lib 文件所需链接到虚拟磁盘 API 函数。 将发布版的更正此问题。 使用测试版的开发人员使用 LoadLibrary 和 GetProcAddress 函数可以加载和地址函数或自己生成 Lib 文件。

将您的问题和提出的意见发送至 mmwincpp@Microsoft.com

通过 Kerr 是一个软件 craftsman 擅长用于 Windows 软件开发中。 他热衷一个用于编写和向有关编程和软件设计的开发人员讲授。 您可以访问在通过 weblogs.asp。 net / kennykerr .


0 0