本文章是由機器翻譯。

使用 C ++ 的 Windows

虛擬磁碟的 API,在 Windows 7

Kenny Kerr

本文根據 Windows 7 鮮版。 本文件的所有資訊都有變更。

內容

VHD) 格式
建立虛擬磁碟
開啟虛擬磁碟
附加虛擬磁碟
查詢虛擬磁碟
下一個

當我寫了這,Windows 7 Beta 版已可用幾天,而且我必須說有許多喜歡。 以平常的方式,我花費底下請參閱是 Windows SDK 中新增一個外觀。 Windows 7 是很大一個次要發行的目前以及 SDK 有關,這是個好方法。 撰寫 Windows 7 的原生 C ++ 應用程式的基礎尚未變更多相較於它們適用於 Windows Vista 中變更的方式。 有說過的但是,Windows 7 具備一些全新功能,確定會感興趣的任何人都想要利用平台。

這些功能之一是虛擬磁碟的 API 時。 雖然設計記住其他格式 Windows 7 Beta 版,虛擬磁碟 API 非常專為 Microsoft 超 V 和 Virtual PC 的虛擬化產品推廣 Microsoft 虛擬硬碟 (VHD) 格式。

這會真的讓我回,因為我已經相關多年來很少數的虛擬化。 當我第一次開始使用虛擬化技術幾乎十年前時,VMware 就會是清除的領導人。 然後在 2003 Microsoft 取得 Connectix,虛擬機器的技術,並所有變更。 突然發生兩個大的播放程式。 已清除 VHD 格式,Microsoft 取得從 Connectix 不適合方向 Microsoft 要採取的虛擬化,也就是,開啟至平台。 而 VMware 虛擬磁碟格式都是專屬] 與 [非常迂迴,通常許多從變更每個發行到下,VHD) 格式會是從一開始簡單而且不夠彈性,來代表時間的測試。 中間年 VHD) 格式證明本身,再一次有已採用其他產品和技術,Microsoft 和其他軟體公司大和小。

因此我快樂,以查看 Windows 7 原本就支援 VHD) 格式。 這表示使用者和系統管理員可以輕鬆地建立並附加虛擬磁碟,如同它們是其他的實體存放裝置,未安裝任何協力廠商的驅動程式或工具。 可以例如您,使用 [磁碟管理 MMC (Microsoft Management Console) 嵌入式管理單元] 或 [DISKPART 命令列工具建立和附加虛擬磁碟。 您可以再磁碟分割,格式化,並像其他任何硬碟磁碟使用在電腦上。

此外,您也可以取得非常細微的控制,建立和管理虛擬磁碟的權。 這些功能的核心可提供一個低階的 C API 的 VirtDisk.dll 稱為虛擬磁碟的 API,建立和管理虛擬磁碟。 這個 API 會提供許多實際上表示磁碟及其儲存子系統中的磁碟區,以便可以檔案系統驅動程式在最上面層而不需要任何的存放區的實際來源的知識時所需的核心模式驅動程式的存取。

磁碟管理 」 工具通常會透過虛擬磁碟服務 (VDS) 本身是依賴虛擬磁碟 API 的處理 VHD-基礎儲存區的虛擬磁碟與互動。 當然超 V 有它自己的 Windows Management Instrumentation (WMI) –based API 建立和管理虛擬的電腦而它太依賴虛擬磁碟的 API。

我在深入,並顯示如何,您可以使用虛擬磁碟的 API 之前,我就將快速說明 VHD) 格式的基本概念。 您會看到指定這個新的 API,您可以現在丟棄的程式碼,您需要之前管理虛擬磁碟。

VHD) 格式

VHD 格式提供三個的不同影像類型: 固定,動態,和差異化磁碟。 所有的三個磁碟類型,包括位於磁碟檔案的結尾 512 位元組 VHD 頁尾。 多對此在一分鐘。

固定的磁碟會都是最簡單的型別,並提供最佳的效能,因為磁碟檔案完全配置以符合要求建立磁碟時的大小。 固定的 500 MB 的磁碟會為位元完全 500 x 1024 x 1024 個 + 512 組的大小。 因為頁尾結尾的磁碟,磁碟的儲存裝置可以對齊,以確保最簡單和最快的可能隨機存取檔案的開頭。

動態磁碟稱為疏鬆的 API,虛擬磁碟的磁碟,並疏鬆是把它們一個好方法。 起初建立時磁碟檔案都具有就足夠空間儲存 VHD 頁尾,以及一些其他中繼資料所需管理儲存區配置的動態性質。 當資料寫入磁碟,磁碟檔案的結尾配置的儲存區的其他區塊。 動態磁碟是有利的它們會佔用遠較少的空間,因為如果沒有使用在完全是這樣的大部分時間的容量。 缺點是中繼資料讀取,所需的管理與其他的間接取值寫入,增加動態磁碟上要求會對效能的付費電話。 環境下較好的為此,動態磁碟會選擇在測試案例,而固定的磁碟偏好在實際執行案例中,因為效能是高的優先順序。

差異化磁碟與動態磁碟非常類似內部,但其他的特性是非常不同。 為動態的磁碟差異磁碟使用,以動態方式配置區塊,但這些區塊包含只與父系磁碟相關的修改。 這種磁碟是因此相依於函式在父系磁碟大小寫的。 可以是差異化磁碟的父代,固定或動態磁碟。 父代事實,可以是另一個的差異化磁碟允許一個鏈結或磁碟來建立樹狀目錄。 表示分葉節點的磁碟可以自由地寫入,但非分葉的節點應該被視為唯讀,因為依賴,填入空格,因此,說的任何子系的差異化磁碟及如果變更很可能會導致損毀的虛擬磁碟。

如我稍早所述,不同的磁碟類型會共用常見的頁尾。 此頁尾會包含磁碟、 磁碟幾何、 磁碟的型別、 磁碟的全域唯一識別項及等等資訊例如邏輯大小。 動態和差異化磁碟,頁尾也會包含指出動態的標頭所在相對於磁碟的開頭的位移的值。 這個第二個結構主要會包含可能需要尋找和識別父系磁碟,必要時,以及另一個指出磁碟的區塊配置表 (BAT) 的所在位置的位移的資訊。 這個資料表可表示的區塊都已配置,以及其絕對的位移,在磁碟檔案中。

開的簡介使用讓我們深入的並看看虛擬磁碟的 API。

請記住 API 為了讓 Microsoft 在未來加入其他格式的支援。 事實上,支援有被視為 ISO 光碟片的影像格式,但尚未加入為 < fa: servicename > Windows 7 Beta。 我希望所需的虛擬磁碟的支援提供者將會包含在發行組建中。 這可讓使用者連接並裝載 ISO 映像,為唯讀的磁碟機。

建立虛擬磁碟

虛擬磁碟是由不透明控制代碼,代表很像其他系統物件例如檔案、 登錄機碼和等等。 即使熟悉 CloseHandle 函數用來關閉虛擬磁碟的控制代碼。 Active Template Library 的 (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 ] 提供包含 CreateFixed 成員函式建立固定虛擬磁碟的 VirtualDisk 包裝函式類別的開端。 請注意若為固定的磁碟您必須指定 CREATE_VIRTUAL_DISK_FLAG_FULL_PHYSICAL_ALLOCATION 旗標。 建立動態的磁碟就是完全不同,您必須省略這個旗標可以時,會指定 CREATE_VIRTUAL_DISK_FLAG_NONE 旗標而建立一個固定的磁碟。 建立差異化磁碟是也比較相同的。 有是您必須不以設定在的大小,差異則從父系磁碟,推斷,而且您必須指定父代,與 ParentPath Version1 結構的成員]。 無法設定 [SourcePath 原因明顯差異磁碟。

[圖 1 建立固定式的磁碟

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 ] 提供的 [開啟] 成員函式,以加入到 VirtualDisk 包裝函式類別,在 [圖 1 ] 中啟動。 開啟虛擬磁碟是通常比建立它們,但必須以允許某些的維護作業,例如合併和附加虛擬磁碟非常特定的方式使用的一些旗標和選項]。

[圖 2 開啟虛擬磁碟

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 的測試) 參數會是您如何控制中附加虛擬磁碟的方法。

[圖 3] 附加磁碟

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 ] 說明此。

[圖 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 格式會提供某種程度的備援,可以利用連結至父代應該中斷。 suffice 就為,父項位置的查詢會包含一連串的空字串結束的 null 結尾字串的剖析。 這是 REG_MULTI_SZ 登錄實值型別相同的。 [圖 5 ] 顯示您如何完成。 範例使用 ATL 的 CAtlArray 集合,以及類別的 ATL CString 類別。

[圖 5 取得父代位置

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 函式。這將會發行的修正。使用 Beta 版的開發人員可以用來載入和函式的位址,或自己產生.lib 檔案的 LoadLibrary 和 GetProcAddress 函式。

您問題或意見寄至mmwincpp@Microsoft.com

Kenny Kerr 會是一個軟體工匠,專精於 Windows 的軟體開發。他有熱情,以寫入的教導有關程式設計和軟體設計的開發人員。您可以與 Kenny 在weblogs.asp。net / kennykerr.