JLION.COM
Creating Volume Shadow Copies from DotNet, Part II
6/18/2009 VB.NET

The Volume Shadow Copy Service, or VSS, has been included with the various flavors of the Windows O/S since Windows XP/Server 2003. It is intended to provide the underlying mechanism for backups.

Due to some tricky COM callbacks, it is very difficult to directly work with the Volume Shadow Copy Service from VB.NET/C#. Microsoft recommends that those needing to do this write a wrapper. vShadow, an unmanaged DLL, is a wrapper intended to make it possible to work with Volume Shadow Copy from VB.NET/C#.

The vShadow wrapper exposed the most important parts of the Windows Volume Shadow Copy service so that volume shadow copies can be made from C# and VB.NET applications. The class also determines the current operating system (XP, Vista, Vista 64, etc.) and uses the correct DLL so that there is no need for multiple releases of the C# or VB.NET application.

With this class and the dlls, you can make a volume shadow copy, copy its contents and dispose it. The vShadow dll does not expose all volume shadow copy functionality: There is no support for writers (the "heads up" that VSS can send to apps such as SQL Server to let them know that a backup is about to occur and that cache should be flushed to disk, etc.) but the most important parts are here.

Using the vShadow DLL is easy. Here's a block of code that creates a shadow copy, copies a file, then disposes of the shadow copy. One caveat: managed code file operations do not work on volume shadow copies, so you can't use the FileInfo and DirInfo classes in the System.IO namespace. Instead, you have to rely on the WIN32 FindFile and CopyFile APIs. I have written classes to encapsulate these functions. If you're interested, you can check them out here. The class also makes use of SystemInfo, a wrapper of the GetNativeSystemInfo API. The SystemInfo class is available here.

    '---It doesn't matter what the path is, since VSS applies to an entire drive (or "volume")
    '   VSS does not work on UNC paths, but "c:\" and "c:\mydata" result in the same VSS image.
    Dim oShadow As New vShadow("c:\") 
                                      
    '---The StartSnapShot function creates the VSS image and, if successful  
    '   returns the path to the volume shadow copy. The path will take the
    '   form of: "\\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy5\jupiter\"                                    
    Dim sShadowPath As String = oShadow.StartSnapShot   

    '---Use the Win32 APIs to locate and copy files
    dim lRet as long=CopyFile(sShadowPath & "myexistingfile.txt","f:\copyofmyfile.txt",1)
    
    '---Shadow copy images must be disposed of properly. 
    oShadow.Dispose()                                   

A zip file containing the vShadow DLLs can be downloaded here. If you would like to discuss obtaining source code for the vShadow DLL or customizing it for your application, please contact me.

Below is vShadow, a VB.NET wrapper class for the vShadow dlls. In order to use the wrapper class, you must place the vShadow dlls in the BIN directory of your NET application.

Imports System.Runtime.InteropServices
Imports System.Threading
Imports System.IO

Namespace file
    Friend Class vShadow
        Private moShadowInterface As ISHADOW

        Private moSnapShotSet As New Guid
        Private moSnapShot As New Guid

        Private msLocalPath As String
        Private msShadowPath As String

        Private Sub InitializeShadowInterface()

            If Not Environment.OSVersion.Platform = PlatformID.Win32NT Then
                Throw New Exception("Volume Shadow Copy not supported on this O/S.")
            Else
                Select Case Environment.OSVersion.Version.Major
                    Case 3
                        '---NT 3.51
                        Throw New Exception("Volume Shadow Copy not supported on this O/S.")

                    Case 4
                        '---NT 4.0
                        Throw New Exception("Volume Shadow Copy not supported on this O/S.")

                    Case 5
                        '---Win2000/XP/2003
                        Select Case Environment.OSVersion.Version.Minor
                            Case 0
                                '---Win2000
                                Throw New Exception("Volume Shadow Copy not supported on this O/S.")

                            Case 1
                                '---WinXP
                                Dim oInfo As New SystemInfo
                                If oInfo.Is64Bit Then
                                    '---64-bit
                                    moShadowInterface = New VSHADOW_XP64
                                Else
                                    '--32-bit
                                    moShadowInterface = New VSHADOW_XP32
                                End If

                            Case 2
                                '---Win2003
                                Dim oInfo As New SystemInfo
                                If oInfo.Is64Bit Then
                                    '---64-bit
                                    moShadowInterface = New VSHADOW_03SVR64

                                Else
                                    '--32-bit
                                    moShadowInterface = New VSHADOW_03SVR32
                                End If

                        End Select

                    Case 6
                        '---Vista/Windows Server 2008
                        Dim oInfo As New SystemInfo
                        If oInfo.Is64Bit Then
                            '---64-bit
                            moShadowInterface = New VSHADOW_VISTA64
                        Else
                            '--32-bit
                            moShadowInterface = New VSHADOW_VISTA32
                        End If

                End Select
            End If
            Select Case Environment.OSVersion.Platform
                Case PlatformID.Win32NT
            End Select
        End Sub

        Public Sub New()
            InitializeShadowInterface()
        End Sub

        Public Sub New(ByVal sPath As String)
            InitializeShadowInterface()

            msLocalPath = sPath

            Dim iIndex As Integer = sPath.IndexOf("\", 0)
            Dim sVolumeName As String = sPath.Substring(0, iIndex + 1)
            msLocalPath = sPath.Substring(iIndex + 1, sPath.Length - iIndex - 1)

            moShadowInterface.VSSInitializeForBackup()
            Dim lRet As Long = moShadowInterface.VSSStartSnapshot(sVolumeName, moSnapShotSet, moSnapShot)
        End Sub

        Public Function StartSnapShot() As String
            Dim sDeviceName As New String(" ", 255)
            Dim lRet As Long = moShadowInterface.VSSGetSnapShotDeviceName(sDeviceName, moSnapShot)

            Return sDeviceName & "\" & msLocalPath
        End Function

        Public Sub Dispose()
            moShadowInterface.VSSDeleteAllSnapshots(moSnapShotSet)
            moShadowInterface.VSSCloseBackup()
        End Sub

        Private Interface ISHADOW
            Function Version() As Integer
            Function VSSInitializeForBackup() As System.UInt32

            Function VSSStartSnapshot( _
                        ByVal pwszVolumeName As String, _
                        ByRef pidSnapShotSet As Guid, _
                        ByRef pidSnapShot As Guid) As System.UInt32

            Function VSSGetSnapShotDeviceName _
                             (ByRef bstrDeviceName As String, _
                              ByRef pidSnapShot As Guid) As System.UInt32

            Function VSSDeleteAllSnapshots _
                         (ByRef pidSnapShotSet As Guid) As System.UInt32

            Function VSSCloseBackup() As System.UInt32
        End Interface

        Private Class VSHADOW_XP32
            Implements ISHADOW

            Private Declare Auto Function _Version Lib "vShadow-xp32.dll" Alias "Version" () As Integer

            Private Declare Auto Function _VSSInitializeForBackup Lib "vShadow-xp32.dll" Alias "VSSInitializeForBackup" () As System.UInt32

            Private Declare Auto Function _VSSStartSnapshot Lib "vShadow-xp32.dll" Alias "VSSStartSnapshot" _
                            ( ByVal pwszVolumeName As String, _
                             ByRef pidSnapShotSet As Guid, _
                             ByRef pidSnapShot As Guid) As System.UInt32

            Private Declare Auto Function _VSSGetSnapShotDeviceName Lib "vShadow-xp32.dll" Alias "VSSGetSnapShotDeviceName" _
                             (<[Out](), MarshalAs(UnmanagedType.BStr)> ByRef bstrDeviceName As String, _
                              ByRef pidSnapShot As Guid) As System.UInt32

            Private Declare Auto Function _VSSDeleteAllSnapshots Lib "vShadow-xp32.dll" Alias "VSSDeleteAllSnapshots" _
                             (ByRef pidSnapShotSet As Guid) As System.UInt32

            Private Declare Auto Function _VSSCloseBackup Lib "vShadow-xp32.dll" Alias "VSSCloseBackup" () As System.UInt32

            Public Function Version() As Integer Implements ISHADOW.Version
                Return _Version
            End Function

            Public Function VSSCloseBackup() As UInteger Implements ISHADOW.VSSCloseBackup
                Return _VSSCloseBackup
            End Function

            Public Function VSSDeleteAllSnapshots(ByRef pidSnapShotSet As System.Guid) As UInteger Implements ISHADOW.VSSDeleteAllSnapshots
                Return _VSSDeleteAllSnapshots(pidSnapShotSet)
            End Function

            Public Function VSSGetSnapShotDeviceName(ByRef bstrDeviceName As String, ByRef pidSnapShot As System.Guid) As UInteger Implements ISHADOW.VSSGetSnapShotDeviceName
                Return _VSSGetSnapShotDeviceName(bstrDeviceName, pidSnapShot)
            End Function

            Public Function VSSInitializeForBackup() As UInteger Implements ISHADOW.VSSInitializeForBackup
                Return _VSSInitializeForBackup
            End Function

            Public Function VSSStartSnapshot(ByVal pwszVolumeName As String, ByRef pidSnapShotSet As System.Guid, ByRef pidSnapShot As System.Guid) As UInteger Implements ISHADOW.VSSStartSnapshot
                Return _VSSStartSnapshot(pwszVolumeName, pidSnapShotSet, pidSnapShot)
            End Function
        End Class

        Private Class VSHADOW_XP64
            Implements ISHADOW

            Private Declare Auto Function _Version Lib "vShadow-xp64.dll" Alias "Version" () As Integer

            Private Declare Auto Function _VSSInitializeForBackup Lib "vShadow-xp64.dll" Alias "VSSInitializeForBackup" () As System.UInt32

            Private Declare Auto Function _VSSStartSnapshot Lib "vShadow-xp64.dll" Alias "VSSStartSnapshot" _
                            ( ByVal pwszVolumeName As String, _
                             ByRef pidSnapShotSet As Guid, _
                             ByRef pidSnapShot As Guid) As System.UInt32

            Private Declare Auto Function _VSSGetSnapShotDeviceName Lib "vShadow-xp64.dll" Alias "VSSGetSnapShotDeviceName" _
                             (<[Out](), MarshalAs(UnmanagedType.BStr)> ByRef bstrDeviceName As String, _
                              ByRef pidSnapShot As Guid) As System.UInt32

            Private Declare Auto Function _VSSDeleteAllSnapshots Lib "vShadow-xp64.dll" Alias "VSSDeleteAllSnapshots" _
                             (ByRef pidSnapShotSet As Guid) As System.UInt32

            Private Declare Auto Function _VSSCloseBackup Lib "vShadow-xp64.dll" Alias "VSSCloseBackup" () As System.UInt32

            Public Function Version() As Integer Implements ISHADOW.Version
                Return _Version
            End Function

            Public Function VSSCloseBackup() As UInteger Implements ISHADOW.VSSCloseBackup
                Return _VSSCloseBackup
            End Function

            Public Function VSSDeleteAllSnapshots(ByRef pidSnapShotSet As System.Guid) As UInteger Implements ISHADOW.VSSDeleteAllSnapshots
                Return _VSSDeleteAllSnapshots(pidSnapShotSet)
            End Function

            Public Function VSSGetSnapShotDeviceName(ByRef bstrDeviceName As String, ByRef pidSnapShot As System.Guid) As UInteger Implements ISHADOW.VSSGetSnapShotDeviceName
                Return _VSSGetSnapShotDeviceName(bstrDeviceName, pidSnapShot)
            End Function

            Public Function VSSInitializeForBackup() As UInteger Implements ISHADOW.VSSInitializeForBackup
                Return _VSSInitializeForBackup
            End Function

            Public Function VSSStartSnapshot(ByVal pwszVolumeName As String, ByRef pidSnapShotSet As System.Guid, ByRef pidSnapShot As System.Guid) As UInteger Implements ISHADOW.VSSStartSnapshot
                Return _VSSStartSnapshot(pwszVolumeName, pidSnapShotSet, pidSnapShot)
            End Function
        End Class

        Private Class VSHADOW_03SVR32
            Implements ISHADOW

            Private Declare Auto Function _Version Lib "vShadow-03svr32.dll" Alias "Version" () As Integer

            Private Declare Auto Function _VSSInitializeForBackup Lib "vShadow-03svr32.dll" Alias "VSSInitializeForBackup" () As System.UInt32

            Private Declare Auto Function _VSSStartSnapshot Lib "vShadow-03svr32.dll" Alias "VSSStartSnapshot" _
                            ( ByVal pwszVolumeName As String, _
                             ByRef pidSnapShotSet As Guid, _
                             ByRef pidSnapShot As Guid) As System.UInt32

            Private Declare Auto Function _VSSGetSnapShotDeviceName Lib "vShadow-03svr32.dll" Alias "VSSGetSnapShotDeviceName" _
                             (<[Out](), MarshalAs(UnmanagedType.BStr)> ByRef bstrDeviceName As String, _
                              ByRef pidSnapShot As Guid) As System.UInt32

            Private Declare Auto Function _VSSDeleteAllSnapshots Lib "vShadow-03svr32.dll" Alias "VSSDeleteAllSnapshots" _
                             (ByRef pidSnapShotSet As Guid) As System.UInt32

            Private Declare Auto Function _VSSCloseBackup Lib "vShadow-03svr32.dll" Alias "VSSCloseBackup" () As System.UInt32

            Public Function Version() As Integer Implements ISHADOW.Version
                Return _Version
            End Function

            Public Function VSSCloseBackup() As UInteger Implements ISHADOW.VSSCloseBackup
                Return _VSSCloseBackup
            End Function

            Public Function VSSDeleteAllSnapshots(ByRef pidSnapShotSet As System.Guid) As UInteger Implements ISHADOW.VSSDeleteAllSnapshots
                Return _VSSDeleteAllSnapshots(pidSnapShotSet)
            End Function

            Public Function VSSGetSnapShotDeviceName(ByRef bstrDeviceName As String, ByRef pidSnapShot As System.Guid) As UInteger Implements ISHADOW.VSSGetSnapShotDeviceName
                Return _VSSGetSnapShotDeviceName(bstrDeviceName, pidSnapShot)
            End Function

            Public Function VSSInitializeForBackup() As UInteger Implements ISHADOW.VSSInitializeForBackup
                Return _VSSInitializeForBackup
            End Function

            Public Function VSSStartSnapshot(ByVal pwszVolumeName As String, ByRef pidSnapShotSet As System.Guid, ByRef pidSnapShot As System.Guid) As UInteger Implements ISHADOW.VSSStartSnapshot
                Return _VSSStartSnapshot(pwszVolumeName, pidSnapShotSet, pidSnapShot)
            End Function
        End Class

        Private Class VSHADOW_03SVR64
            Implements ISHADOW

            Private Declare Auto Function _Version Lib "vShadow-03svr64.dll" Alias "Version" () As Integer

            Private Declare Auto Function _VSSInitializeForBackup Lib "vShadow-03svr64.dll" Alias "VSSInitializeForBackup" () As System.UInt32

            Private Declare Auto Function _VSSStartSnapshot Lib "vShadow-03svr64.dll" Alias "VSSStartSnapshot" _
                            ( ByVal pwszVolumeName As String, _
                             ByRef pidSnapShotSet As Guid, _
                             ByRef pidSnapShot As Guid) As System.UInt32

            Private Declare Auto Function _VSSGetSnapShotDeviceName Lib "vShadow-03svr64.dll" Alias "VSSGetSnapShotDeviceName" _
                             (<[Out](), MarshalAs(UnmanagedType.BStr)> ByRef bstrDeviceName As String, _
                              ByRef pidSnapShot As Guid) As System.UInt32

            Private Declare Auto Function _VSSDeleteAllSnapshots Lib "vShadow-03svr64.dll" Alias "VSSDeleteAllSnapshots" _
                             (ByRef pidSnapShotSet As Guid) As System.UInt32

            Private Declare Auto Function _VSSCloseBackup Lib "vShadow-03svr64.dll" Alias "VSSCloseBackup" () As System.UInt32

            Public Function Version() As Integer Implements ISHADOW.Version
                Return _Version
            End Function

            Public Function VSSCloseBackup() As UInteger Implements ISHADOW.VSSCloseBackup
                Return _VSSCloseBackup
            End Function

            Public Function VSSDeleteAllSnapshots(ByRef pidSnapShotSet As System.Guid) As UInteger Implements ISHADOW.VSSDeleteAllSnapshots
                Return _VSSDeleteAllSnapshots(pidSnapShotSet)
            End Function

            Public Function VSSGetSnapShotDeviceName(ByRef bstrDeviceName As String, ByRef pidSnapShot As System.Guid) As UInteger Implements ISHADOW.VSSGetSnapShotDeviceName
                Return _VSSGetSnapShotDeviceName(bstrDeviceName, pidSnapShot)
            End Function

            Public Function VSSInitializeForBackup() As UInteger Implements ISHADOW.VSSInitializeForBackup
                Return _VSSInitializeForBackup
            End Function

            Public Function VSSStartSnapshot(ByVal pwszVolumeName As String, ByRef pidSnapShotSet As System.Guid, ByRef pidSnapShot As System.Guid) As UInteger Implements ISHADOW.VSSStartSnapshot
                Return _VSSStartSnapshot(pwszVolumeName, pidSnapShotSet, pidSnapShot)
            End Function
        End Class

        Private Class VSHADOW_VISTA32
            Implements ISHADOW

            Private Declare Auto Function _Version Lib "vShadow-Vista32.dll" Alias "Version" () As Integer

            Private Declare Auto Function _VSSInitializeForBackup Lib "vShadow-Vista32.dll" Alias "VSSInitializeForBackup" () As System.UInt32

            Private Declare Auto Function _VSSStartSnapshot Lib "vShadow-Vista32.dll" Alias "VSSStartSnapshot" _
                            ( ByVal pwszVolumeName As String, _
                             ByRef pidSnapShotSet As Guid, _
                             ByRef pidSnapShot As Guid) As System.UInt32

            Private Declare Auto Function _VSSGetSnapShotDeviceName Lib "vShadow-Vista32.dll" Alias "VSSGetSnapShotDeviceName" _
                             (<[Out](), MarshalAs(UnmanagedType.BStr)> ByRef bstrDeviceName As String, _
                              ByRef pidSnapShot As Guid) As System.UInt32

            Private Declare Auto Function _VSSDeleteAllSnapshots Lib "vShadow-Vista32.dll" Alias "VSSDeleteAllSnapshots" _
                             (ByRef pidSnapShotSet As Guid) As System.UInt32

            Private Declare Auto Function _VSSCloseBackup Lib "vShadow-Vista32.dll" Alias "VSSCloseBackup" () As System.UInt32

            Public Function Version() As Integer Implements ISHADOW.Version
                Return _Version
            End Function

            Public Function VSSCloseBackup() As UInteger Implements ISHADOW.VSSCloseBackup
                Return _VSSCloseBackup
            End Function

            Public Function VSSDeleteAllSnapshots(ByRef pidSnapShotSet As System.Guid) As UInteger Implements ISHADOW.VSSDeleteAllSnapshots
                Return _VSSDeleteAllSnapshots(pidSnapShotSet)
            End Function

            Public Function VSSGetSnapShotDeviceName(ByRef bstrDeviceName As String, ByRef pidSnapShot As System.Guid) As UInteger Implements ISHADOW.VSSGetSnapShotDeviceName
                Return _VSSGetSnapShotDeviceName(bstrDeviceName, pidSnapShot)
            End Function

            Public Function VSSInitializeForBackup() As UInteger Implements ISHADOW.VSSInitializeForBackup
                Return _VSSInitializeForBackup
            End Function

            Public Function VSSStartSnapshot(ByVal pwszVolumeName As String, ByRef pidSnapShotSet As System.Guid, ByRef pidSnapShot As System.Guid) As UInteger Implements ISHADOW.VSSStartSnapshot
                Return _VSSStartSnapshot(pwszVolumeName, pidSnapShotSet, pidSnapShot)
            End Function
        End Class

        Private Class VSHADOW_VISTA64
            Implements ISHADOW

            Private Declare Auto Function _Version Lib "vShadow-Vista64.dll" Alias "Version" () As Integer

            Private Declare Auto Function _VSSInitializeForBackup Lib "vShadow-Vista64.dll" Alias "VSSInitializeForBackup" () As System.UInt32

            Private Declare Auto Function _VSSStartSnapshot Lib "vShadow-Vista64.dll" Alias "VSSStartSnapshot" _
                            ( ByVal pwszVolumeName As String, _
                             ByRef pidSnapShotSet As Guid, _
                             ByRef pidSnapShot As Guid) As System.UInt32

            Private Declare Auto Function _VSSGetSnapShotDeviceName Lib "vShadow-Vista64.dll" Alias "VSSGetSnapShotDeviceName" _
                             (<[Out](), MarshalAs(UnmanagedType.BStr)> ByRef bstrDeviceName As String, _
                              ByRef pidSnapShot As Guid) As System.UInt32

            Private Declare Auto Function _VSSDeleteAllSnapshots Lib "vShadow-Vista64.dll" Alias "VSSDeleteAllSnapshots" _
                             (ByRef pidSnapShotSet As Guid) As System.UInt32

            Private Declare Auto Function _VSSCloseBackup Lib "vShadow-Vista64.dll" Alias "VSSCloseBackup" () As System.UInt32

            Public Function Version() As Integer Implements ISHADOW.Version
                Return _Version
            End Function

            Public Function VSSCloseBackup() As UInteger Implements ISHADOW.VSSCloseBackup
                Return _VSSCloseBackup
            End Function

            Public Function VSSDeleteAllSnapshots(ByRef pidSnapShotSet As System.Guid) As UInteger Implements ISHADOW.VSSDeleteAllSnapshots
                Return _VSSDeleteAllSnapshots(pidSnapShotSet)
            End Function

            Public Function VSSGetSnapShotDeviceName(ByRef bstrDeviceName As String, ByRef pidSnapShot As System.Guid) As UInteger Implements ISHADOW.VSSGetSnapShotDeviceName
                Return _VSSGetSnapShotDeviceName(bstrDeviceName, pidSnapShot)
            End Function

            Public Function VSSInitializeForBackup() As UInteger Implements ISHADOW.VSSInitializeForBackup
                Return _VSSInitializeForBackup
            End Function

            Public Function VSSStartSnapshot(ByVal pwszVolumeName As String, ByRef pidSnapShotSet As System.Guid, ByRef pidSnapShot As System.Guid) As UInteger Implements ISHADOW.VSSStartSnapshot
                Return _VSSStartSnapshot(pwszVolumeName, pidSnapShotSet, pidSnapShot)
            End Function
        End Class
    End Class
End Namespace