How to backup files in C++ using the volume shadow copy service (VSS)

If you’re writing a backup program, you need to be able to read and access files that are in use by other programs. The proper way to do this is to use the Volume Shadow Copy Service. The MSDN pages cover a lot of material that is unnecessary for a simple backup program, so here are some simple steps to get you started.

Before you start: important notes

  • This article assumes that you are using Windows Vista or later. For Windows XP, you may need to make some modifications to this code.
  • You cannot use VSS from a 32-bit program running under a 64-bit version of Windows. On 64-bit Windows, you need to compile a 64-bit version of your program.
  • Usually, your program needs to run under an administrator account. If UAC is enabled, your program needs to be elevated.

Step 1. Initialize backup components

You need to have access to these two functions: CreateVssBackupComponents, VssFreeSnapshotProperties. If you want, you can link to VssApi.lib. Here I will be using GetProcAddress instead. Start with some basic imports and definitions:

#include <vss.h>
#include <vswriter.h>
#include <vsbackup.h>

typedef HRESULT (STDAPICALLTYPE *_CreateVssBackupComponentsInternal)(
    __out IVssBackupComponents **ppBackup
    );

typedef void (APIENTRY *_VssFreeSnapshotPropertiesInternal)(
    __in VSS_SNAPSHOT_PROP *pProp
    );

static _CreateVssBackupComponentsInternal CreateVssBackupComponentsInternal_I;
static _VssFreeSnapshotPropertiesInternal VssFreeSnapshotPropertiesInternal_I;

Note that the functions have “Internal” at the end. Now get the functions and create your IVssBackupComponents object:

HRESULT result;
HMODULE vssapiBase;
IVssBackupComponents *backupComponents;

vssapiBase = LoadLibrary(L"vssapi.dll");

if (vssapiBase)
{
    CreateVssBackupComponentsInternal_I = (_CreateVssBackupComponentsInternal)GetProcAddress(vssapiBase, "CreateVssBackupComponentsInternal");
    VssFreeSnapshotPropertiesInternal_I = (_VssFreeSnapshotPropertiesInternal)GetProcAddress(vssapiBase, "VssFreeSnapshotPropertiesInternal");
}

if (!CreateVssBackupComponentsInternal_I || !VssFreeSnapshotPropertiesInternal_I)
    abort(); // Handle error

result = CreateVssBackupComponentsInternal_I(&backupComponents);

if (!SUCCEEDED(result))
    abort(); // Handle error

Step 2. Connect to VSS

Nothing interesting here.

VSS_ID snapshotSetId;

result = backupComponents->InitializeForBackup();

if (!SUCCEEDED(result))
    abort(); // If you don't have admin privileges or your program is running under WOW64, it will fail here

result = backupComponents->SetBackupState(FALSE, FALSE, VSS_BT_INCREMENTAL);

if (!SUCCEEDED(result))
    abort(); // Handle error

result = backupComponents->SetContext(VSS_CTX_FILE_SHARE_BACKUP);

if (!SUCCEEDED(result))
    abort(); // Handle error

return backupComponents->StartSnapshotSet(&snapshotSetId);

Step 3. Add the volumes

Now you need to add the volumes that you’re interested in by calling AddToSnapshotSet. This will give you a snapshot ID that you need to save. Make sure your volume name has a trailing backslash. In this article we’ll assume that you only have one volume that you’re interested in, but you can add as many as you want.

VSS_ID snapshotId;

result = backupComponents->AddToSnapshotSet(L"D:\\", GUID_NULL, &snapshotId);

if (!SUCCEEDED(result))
    abort(); // Handle error

Step 4. Perform the snapshot

Once you have added your volumes, you need to perform the snapshot using DoSnapshotSet:

IVssAsync *async;

result = backupComponents->DoSnapshotSet(&async);

if (!SUCCEEDED(result))
    abort(); // Handle error

result = async->Wait();
async->Release();

if (!SUCCEEDED(result))
    abort(); // Handle error

Step 5. Use the snapshot(s)

Your snapshot(s) are now ready. For each of the volumes, call GetSnapshotProperties to get a VSS_SNAPSHOT_PROP structure. Use the m_pwszSnapshotDeviceObject field to get the device name (e.g. “\Device\HarddiskVolumeShadowCopy1”) for your snapshot. If you created a snapshot for D:\ and you want to access D:\somefile.txt, open \Device\HarddiskVolumeShadowCopy1\somefile.txt.

VSS_SNAPSHOT_PROP prop;

result = backupComponents->GetSnapshotProperties(snapshotId, &prop);

if (!SUCCEEDED(result))
    abort(); // Handle error

// Use prop.m_pwszSnapshotDeviceObject to access your files.

VssFreeSnapshotPropertiesInternal_I(&prop);

Step 6. Cleaning up

You just need one line:

backupComponents->Release();

For more information:

Please leave a comment if you have any questions.

One response

Leave a Reply