从 .NET 使用卷影副本
从 .NET 使用 Windows 卷影复制服务。
引言
如果您想自动备份锁定文件,例如 Microsoft Outlook PST 文件,您会发现您的选择似乎仅限于专用的备份实用程序,例如 Microsoft Backup。但是,如果您只想备份 PST 文件,并且希望备份副本立即可用,而不是压缩在 BKF 文件中,该怎么办呢?
Microsoft 卷影复制服务 是解决此问题的方案。这就是 Microsoft Backup 和其他备份实用程序能够复制锁定文件的方式。
有一个 卷影复制服务 SDK 和 MSDN 上的文档,但如何使用 .NET 实现 VSC,甚至是否可行,都远不清楚。在 Craig Andera 的博客 的一些帮助下,我发现这是可行的,我将在下面向您展示如何操作。
背景
当我第一次开始研究卷影复制时,我并不确定从哪里开始。我以为我可能需要创建和注册一个提供程序。但是后来 Craig Andera 的 HOBOCOPY 博客文章的一位评论者提到了一个 **VSSCoordinatorClass
**,事实证明这正是我需要的。
VSSCoordinatorClass
似乎没有文档记录。如果我在 Google 上搜索它,我得到的是最初的博客评论以及一两个其他非官方且不太有用的参考资料。MSDN 也对此没有任何说明。此类似乎公开了 IVssBackupComponents
接口的方法,而这正是您创建卷影副本所需的方法。
特别是,要创建卷影副本,您需要采取以下步骤:
- 使用
StartSnapshotSet
创建快照集 - 使用
AddToSnapshotSet
将卷添加到快照集 - 使用
DoSnapshotSet
初始化卷快照 - 等待
QueryStatus
指示快照已初始化 - 使用
GetSnapshotProperties
获取快照的卷名 - 使用
FindFile
和CopyFile
API 访问卷影卷 - 完成后,使用
DeleteSnapshots
方法指示不再需要卷影卷
使用代码
附加的源代码是一个简单的实用程序,它扫描源目录和任何子目录中的 PST 文件。找到的任何 PST 文件都将复制到目标目录。
要使用此实用程序,请从 Zip 文件中解压缩文件。使用以下参数运行 *makeshadowcopy.exe*
- -F: 指示“来自”目录。例如:*C:\Documents and Settings\ttyree\Local Settings\Application Data\Microsoft\Outlook*
- -T: 指示“到”目录。例如:*C:\tedsoutlookbackup*
请注意,默认情况下,这两个 Windows 服务设置为“手动”,需要启动才能使卷影复制正常工作
- 卷影复制服务
- MS 软件卷影复制提供程序
示例实用程序中的大部分代码都是标准的,我不会尝试解释如何使用 FindFirstFile
和 CopyFile
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 备份实用程序的范围有关。由于我主要将此实用程序包含为卷影副本用途的演示,因此此类改进超出了本项目的范围。