Email:
Password:
Email:
JLION.COM
01/07/2008 updated 6/18/2008 VB.NET

Creating Volume Shadow Copies from DotNet

The Volume Shadow Copy service first came to my attention about two years ago when I was trying to find a way to back up PST files without using Microsoft Backup or similar.

At the time I looked at it, it seemed to time consuming and complicated to implement but I was intrigued and didn't forget about it. Then, over the holidays, I decided to reinvestigate. A blog posting on Craig Andrea's blog conveninentlyl pointed me in the right direction and what had seemed to be an intimidatingly complicated undertaking suddenly was reduced to a few hours' tinkering.

NOTE: Some time after writing this, I put together a C wrapper class for the VSS functions. This wrapper class supports more operating systems than the VSSCoordinator class on which the following article is based, and a wrapper class is the recommended Microsoft approach for using VSS in managed applications. The class and source code are available for download here.

Since there there seems to be very little out there on the web at present that talks about using Volume Shadow Copy with DotNet, I've decided to share the results of my tinkering. I put together a simple sample console utility for the backing up of PST files and have posted the utility along with some commentary and the VB.NET class that implements Volume Shadow Copy on the CodeProject web site.

I also am replicating the class code here below. This is the results of a few hours of tinkering and has not been tested extensively, so if you do use this class or some derivitative and encounter problems, please do let me know.

NOTE: I've done some minimal testing with XP sp2 and with Windows Server 2003 and it seems like there are different versions of the COM object for these two operating systems. IE: I was not able to use the same compiled program on both OS platforms, but if I compiled the program under Windows Server 2003 and created a setup there, then the program installed by the setup would work on a fresh Windows Server install. That same install would not work on XP2, but the program were compiled on XP2 then it would run in that OS.

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 Enum _VSS_OBJECT_TYPE As Byte
            VSS_OBJECT_UNKNOWN = 0
            VSS_OBJECT_NONE = 1
            VSS_OBJECT_SNAPSHOT_SET = 2
            VSS_OBJECT_SNAPSHOT = 3
            VSS_OBJECT_PROVIDER = 4
            VSS_OBJECT_TYPE_COUNT = 5
        End Enum
    
        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

 

Created by Joe Lynds 2002-2008. Contact Joe
http://www.jlion.com