65.9K
CodeProject 正在变化。 阅读更多。
Home

从 .NET 使用卷影副本

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.85/5 (12投票s)

2008年1月7日

Ms-PL

3分钟阅读

viewsIcon

185113

downloadIcon

3546

从 .NET 使用 Windows 卷影复制服务。

引言

如果您想自动备份锁定文件,例如 Microsoft Outlook PST 文件,您会发现您的选择似乎仅限于专用的备份实用程序,例如 Microsoft Backup。但是,如果您只想备份 PST 文件,并且希望备份副本立即可用,而不是压缩在 BKF 文件中,该怎么办呢?

Microsoft 卷影复制服务 是解决此问题的方案。这就是 Microsoft Backup 和其他备份实用程序能够复制锁定文件的方式。

有一个 卷影复制服务 SDKMSDN 上的文档,但如何使用 .NET 实现 VSC,甚至是否可行,都远不清楚。在 Craig Andera 的博客 的一些帮助下,我发现这是可行的,我将在下面向您展示如何操作。

背景

当我第一次开始研究卷影复制时,我并不确定从哪里开始。我以为我可能需要创建和注册一个提供程序。但是后来 Craig Andera 的 HOBOCOPY 博客文章的一位评论者提到了一个 **VSSCoordinatorClass**,事实证明这正是我需要的。

VSSCoordinatorClass 似乎没有文档记录。如果我在 Google 上搜索它,我得到的是最初的博客评论以及一两个其他非官方且不太有用的参考资料。MSDN 也对此没有任何说明。此类似乎公开了 IVssBackupComponents 接口的方法,而这正是您创建卷影副本所需的方法。

特别是,要创建卷影副本,您需要采取以下步骤:

  1. 使用 StartSnapshotSet 创建快照集
  2. 使用 AddToSnapshotSet 将卷添加到快照集
  3. 使用 DoSnapshotSet 初始化卷快照
  4. 等待 QueryStatus 指示快照已初始化
  5. 使用 GetSnapshotProperties 获取快照的卷名
  6. 使用 FindFileCopyFile API 访问卷影卷
  7. 完成后,使用 DeleteSnapshots 方法指示不再需要卷影卷

使用代码

附加的源代码是一个简单的实用程序,它扫描源目录和任何子目录中的 PST 文件。找到的任何 PST 文件都将复制到目标目录。

要使用此实用程序,请从 Zip 文件中解压缩文件。使用以下参数运行 *makeshadowcopy.exe*

  • -F: 指示“来自”目录。例如:*C:\Documents and Settings\ttyree\Local Settings\Application Data\Microsoft\Outlook*
  • -T: 指示“到”目录。例如:*C:\tedsoutlookbackup*

请注意,默认情况下,这两个 Windows 服务设置为“手动”,需要启动才能使卷影复制正常工作

  • 卷影复制服务
  • MS 软件卷影复制提供程序

示例实用程序中的大部分代码都是标准的,我不会尝试解释如何使用 FindFirstFileCopyFile API。我确实将卷影复制封装为一个类,并在此处发布供您查看。

此类使用卷名(例如:“C:”或“E:”)实例化,一旦实例化,DeviceName 属性将返回卷影卷的名称。完成卷影卷后,使用 Delete 方法释放它。

Public Class Snapshot
    'Note:  The following two windows services are stopped by default.
    '       For volume shadow copy to function
    '       they need to be started.

    '       Volume Shadow Copy service
    '       MS Software Shadow Copy Provider

    'Technet article describing how Volume Shadow Copy works:
    'http://technet2.microsoft.com/windowsserver/en/library/
    '     2b0d2457-b7d8-42c3-b6c9-59c145b7765f1033.mspx?mfr=true

    'Thanks to Craig Andera for his HOBOCOPY blog 
    'posting which provided the basis for this code.
    'http://www.pluralsight.com/blogs/craig/archive/2006/09/20/38362.aspx

    'Note: More information about programming 
    '      the volume shadow copy service is available here:
    'http://msdn2.microsoft.com/en-us/library/aa384649.aspx

    'Note: The microsoft volume shadow copy service 
    '      SDK with headers and utilties is available here:
    'http://www.microsoft.com/downloads/details.aspx?
    '     FamilyID=0B4F56E4-0CCC-4626-826A-ED2C4C95C871&displaylang=en

    Private Const VSS_E_BAD_STATE = &H80042301
    Private Const VSS_E_PROVIDER_ALREADY_REGISTERED = &H80042303
    Private Const VSS_E_PROVIDER_NOT_REGISTERED = &H80042304
    Private Const VSS_E_PROVIDER_VETO = &H80042306
    Private Const VSS_E_PROVIDER_IN_USE = &H80042307
    Private Const VSS_E_OBJECT_NOT_FOUND = &H80042308
    Private Const VSS_S_ASYNC_PENDING = &H42309
    Private Const VSS_S_ASYNC_FINISHED = &H4230A
    Private Const VSS_S_ASYNC_CANCELLED = &H4230B
    Private Const VSS_E_VOLUME_NOT_SUPPORTED = &H8004230C
    Private Const VSS_E_VOLUME_NOT_SUPPORTED_BY_PROVIDER = &H8004230E
    Private Const VSS_E_OBJECT_ALREADY_EXISTS = &H8004230D
    Private Const VSS_E_UNEXPECTED_PROVIDER_ERROR = &H8004230F
    Private Const VSS_E_CORRUPT_XML_DOCUMENT = &H80042310
    Private Const VSS_E_INVALID_XML_DOCUMENT = &H80042311
    Private Const VSS_E_MAXIMUM_NUMBER_OF_VOLUMES_REACHED = &H80042312
    Private Const VSS_E_FLUSH_WRITES_TIMEOUT = &H80042313
    Private Const VSS_E_HOLD_WRITES_TIMEOUT = &H80042314
    Private Const VSS_E_UNEXPECTED_WRITER_ERROR = &H80042315
    Private Const VSS_E_SNAPSHOT_SET_IN_PROGRESS = &H80042316
    Private Const VSS_E_MAXIMUM_NUMBER_OF_SNAPSHOTS_REACHED = &H80042317
    Private Const VSS_E_WRITER_INFRASTRUCTURE = &H80042318
    Private Const VSS_E_WRITER_NOT_RESPONDING = &H80042319
    Private Const VSS_E_WRITER_ALREADY_SUBSCRIBED = &H8004231A
    Private Const VSS_E_UNSUPPORTED_CONTEXT = &H8004231B
    Private Const VSS_E_VOLUME_IN_USE = &H8004231D
    Private Const VSS_E_MAXIMUM_DIFFAREA_ASSOCIATIONS_REACHED = &H8004231E
    Private Const VSS_E_INSUFFICIENT_STORAGE = &H8004231F
    Private Const VSS_E_NO_SNAPSHOTS_IMPORTED = &H80042320
    Private Const VSS_S_SOME_SNAPSHOTS_NOT_IMPORTED = &H42320

    Private moSnapshotSetID As New Guid
    Private moSnapshotID As New Guid
    Private msDeviceName As String

    Public Sub New(ByVal sVolume As String)
        Dim vss As New VSS.VSSCoordinatorClass

        Abort(vss)
        MakeNewSnapshot(vss, sVolume, moSnapshotSetID, moSnapshotID)
        msDeviceName = GetSnapshotDeviceName(vss, moSnapshotID)
    End Sub

    Public ReadOnly Property DeviceName() As String
        Get
            Return msDeviceName
        End Get
    End Property

    Private Sub MakeNewSnapshot( _
                ByRef vss As VSS.VSSCoordinatorClass, _
                ByVal sVolume As String, _
                ByRef output_SnapShotSetID As Guid, _
                ByRef output_SnapShotID As Guid)

        vss.StartSnapshotSet(output_SnapShotSetID)
        vss.AddToSnapshotSet(sVolume, Guid.Empty, output_SnapShotID)

        Dim ovssAsync As VSS.IVssAsync = Nothing
        Dim oCallBack As Object = Nothing

        vss.DoSnapshotSet(oCallBack, ovssAsync)

        Do While (True)
            Dim hr As Integer = 0
            Dim x As Integer = 0

            ovssAsync.QueryStatus(hr, x)
            Console.Write(".")

            If hr = VSS_S_ASYNC_FINISHED Then
                Exit Do
            End If

            Thread.Sleep(1000)
        Loop

        Console.WriteLine()
    End Sub

    Private Function GetSnapshotDeviceName( _
                    ByRef vss As VSS.VSSCoordinatorClass, _
                    ByVal oSnapShotID As Guid) As String

        Dim sDeviceName As String = ""

        Dim osnapshotProps As New VSS._VSS_SNAPSHOT_PROP
        vss.GetSnapshotProperties(oSnapShotID, osnapshotProps)
        sDeviceName = osnapshotProps.m_pwszSnapshotDeviceObject

        Return sDeviceName
    End Function

    Private Sub Abort( _
                ByRef vss As VSS.VSSCoordinatorClass)

        '   Aborting VSS Operations
        '   http://msdn2.microsoft.com/en-us/library/aa381496(VS.85).aspx

        '---Only one snapshot can be operating at a time,
        '   so abort any current snapshots.

        vss.AbortAllSnapshotsInProgress()
    End Sub

    Public Sub Delete()
        Dim iCountOfDeletedSnapshots As Integer = 0
        Dim oNonDeletedSnapshotID As New Guid

        Dim vss As New VSS.VSSCoordinatorClass
        vss.DeleteSnapshots( _
                moSnapshotSetID, _
                _VSS_OBJECT_TYPE.VSS_OBJECT_SNAPSHOT_SET, _
                True, _
                iCountOfDeletedSnapshots, _
                oNonDeletedSnapshotID)
    End Sub
End Class

可能的改进

这里可以做很多事情,最重要的是更好的错误处理。一次只能打开一个卷影卷,如果应用程序尝试初始化卷影卷时遇到任何类型的错误,它将崩溃并显示一条难看的错误消息。处理此错误和其他可能的错误将是一个巨大的进步。

其他改进更多地与 PST 备份实用程序的范围有关。由于我主要将此实用程序包含为卷影副本用途的演示,因此此类改进超出了本项目的范围。

© . All rights reserved.