I recently spent time investigating the Volume Shadow Copy Service(VSS) and found that it was very confusing. I just needed to be able to copy files that were locked by other applications and VSS seemed like the way to go.
As I was starting out trying to get my sample working, I ran into a couple of problems. The problems occurred when I would call the InitializeForBackup function from the IVssBackupComponent interface. It would return the value 0×80042302. When I looked in vsserror.h, that value was skipped:
//
// MessageId: VSS_E_BAD_STATE
//
// MessageText:
//
// A function call was made when the object was in an incorrect state
// for that function
//
#define VSS_E_BAD_STATE ((HRESULT)0x80042301L)
//
// MessageId: VSS_E_PROVIDER_ALREADY_REGISTERED
//
// MessageText:
//
// The provider has already been registered.
//
#define VSS_E_PROVIDER_ALREADY_REGISTERED ((HRESULT)0x80042303L)
I discovered later that the value was defined in V7 of the SDK and it is defined as VSS_E_UNEXPECTED and it simply meant to check the application event logs for more information.
So I checked the Application Log and was getting the following error.
Volume Shadow Copy Service error: Unexpected error calling routine CoCreateInstance. hr = 0x800401f0, CoInitialize has not been called.
.
Operation:
Initialize For Backup
I did some searches and eventually found a forum post that said to make sure that the “Volume Shadow Copy”, “COM+ System Application”, and the “Distributed Transaction Coordinator” services were running. My “COM+ System Application” service was not running, so I started it and it fixed that problem.
But then another error occurred:
Volume Shadow Copy Service error: A critical component required by the Volume Shadow Copy service is not registered. This might happened if an error occurred during Windows setup or during installation of a Shadow Copy provider. The error returned from CoCreateInstance on class with CLSID {e579ab5f-1cc4-44b4-bed9-de0991ff0623} and Name IVssCoordinatorEx2 is [0x80040154, Class not registered].
Operation:
Instantiating VSS server
I figured out that this was being caused because I was making my application a 32-bit application running on a 64-bit OS. The documentation specifically says “All 32-bit VSS applications (requesters, providers, and writers) must run as native 32-bit or 64-bit applications. Running them under WOW64 is not supported.” and this is what happens when you ignore it.
So I was about 90% of the way finished, but the last part of actually doing the file copy was a little unclear, so after a little bit of searching, I found the VShadow sample project in the Volume Shadow Copy Service SDK 7.2 which seemed like it would be perfect for my needs. Well, it’s a very powerful tool, but it really wasn’t that clear on how to use this utility to copy a file either.
I felt like I was getting very close!
After a little more searching, I found SCRIPT RECIPE OF THE WEEK: HOW TO COPY AN OPENED FILE which gave me the information needed on how to call VShadow, along with other cool features like how to recursively call your script. It worked, but there were still a few problems like not being able to use it from a long file path with spaces and it also wouldn’t copy hidden files.
But based on how this script called VShadow, I was able to figure out my missing piece and finished this sample.
So, in a nutshell, this is a sample of how to copy a single locked file:
LockeFileCopy.cpp
#include <stdio.h>
#include <tchar.h>
#include <shlwapi.h>
#include <vss.h>
#include <vswriter.h>
#include <vsbackup.h>
int _tmain(int argc, _TCHAR* argv[])
{
int returnValue = 1;
if (argc != 3)
{
printf("Usage: LockedFileCopy.exe sourcefile destinationfile\n");
return 1;
}
TCHAR sourceFile[_MAX_PATH] = {0};
LPTSTR destinationFile = argv[2];
//
// Create an absolute path if it is relative
//
_tcscpy(sourceFile, argv[1]);
if (PathIsRelative(sourceFile))
{
::PathFindFileName(sourceFile);
}
if (_taccess(sourceFile,0) != 0)
{
_tprintf(_T("\"%s\" does not exist!\n"), argv[1]);
return 1;
}
if (CoInitialize(NULL) != S_OK)
{
printf("CoInitialize failed!\n");
return 1;
}
//
// Create the IVssBackupComponents Interface
//
IVssBackupComponents *pBackup = NULL;
HRESULT result = CreateVssBackupComponents(&pBackup);
if (result == S_OK)
{
//
// Initialize for backup
//
result = pBackup->InitializeForBackup();</code>
if (result == S_OK)
{
//
// Prompts each writer to send the metadata they have collected
//
IVssAsync *pAsync = NULL;
result = pBackup->GatherWriterMetadata(&pAsync);
if (result == S_OK)
{
printf("Gathering metadata from writers...\n");
result = pAsync->Wait();
if (result == S_OK)
{
//
// Creates a new, empty shadow copy set
//
VSS_ID snapshotSetId;
result = pBackup->StartSnapshotSet(&snapshotSetId);
if (result == S_OK)
{
//
// Add Volume to the shadow copy set
//
WCHAR volumeName[4] = {sourceFile[0], _T(':'), _T("\\")};
wprintf(L"Adding %s volume to snapshot set...\n", volumeName);
result = pBackup->AddToSnapshotSet(volumeName, GUID_NULL, &snapshotSetId);
if (result == S_OK)
{
//
// Configure the backup operation for Copy with no backup history
//
result = pBackup->SetBackupState(false, false, VSS_BT_COPY);
if (result == S_OK)
{
//
// Make VSS generate a PrepareForBackup event
//
IVssAsync* pPrepare = NULL;
result = pBackup->PrepareForBackup(&pPrepare);
if (result == S_OK)
{
printf("Preparing for backup...\n");
result = pPrepare->Wait();
if (result == S_OK)
{
//
// Commit all snapshots in this set
//
IVssAsync* pDoShadowCopy = NULL;
result = pBackup->DoSnapshotSet(&pDoShadowCopy);
if (result == S_OK)
{
printf("Taking snapshots...\n");
result = pDoShadowCopy->Wait();
if (result == S_OK)
{
//
// Get the snapshot device object from the properties
//
VSS_SNAPSHOT_PROP snapshotProp = {0};
result = pBackup->GetSnapshotProperties(snapshotSetId, &snapshotProp);
if (result == S_OK)
{
//
// Create the source path by using the volume specified in
// m_pwszSnapshotDeviceObject and appending the path of
// the source file (minus the drive letter)
//
int sourceLength = wcslen(snapshotProp.m_pwszSnapshotDeviceObject) +
_tcslen(sourceFile);
LPTSTR sourceSnapshotFile = new TCHAR[sourceLength];
_tcscpy_s(sourceSnapshotFile, sourceLength,
snapshotProp.m_pwszSnapshotDeviceObject);
_tcscat_s(sourceSnapshotFile, sourceLength, &sourceFile[2]);</code>
//
// Copy the file from the snapshot device object
//
if (!::CopyFile(sourceSnapshotFile, destinationFile, FALSE))
{
DWORD lastError = GetLastError();
printf("Failed to copy file - Error: %d\n", lastError);
}
else
{
printf("Successfully copied file!\n");
returnValue = 0;
}
delete [] sourceSnapshotFile;</code>
//
// Cleanup properties
//
VssFreeSnapshotProperties(&snapshotProp);
}
}
pDoShadowCopy->Release();
}
}
pPrepare->Release();
}
}
}
//
// Delete the snapshot
//
LONG deletedSnapshots = 0;
VSS_ID nonDeletedSnapshotId;
result = pBackup->DeleteSnapshots(snapshotSetId, VSS_OBJECT_SNAPSHOT,
TRUE, &deletedSnapshots, &nonDeletedSnapshotId);
}
}
pAsync->Release();
}
}
pBackup->Release();
}
return returnValue;
}
Very helpful, I was trying to do just this but the COM interface was just indecipherable. So, thanks a lot !
Thanks!!!
Excellent article, just what I was looking for! There’s a real lack of information about VSS and the documentation is very confusing.
I am having a problem with the call to CreateVssBackupComponents(), it always returns E_ACCESSDENIED when running as my login. I have used AdjustTokenPrivilege() to set SE_BACKUP_NAME privilege to enabled but still the same. Do you have any ideas on why I can’t run this function?
What OS are you developing on?
Should have mentioned, I’m developing in Windows 7 but my software will need to support back to XP.
Thank You for the sample code. I too am facing the same problem that Jason(above) faced. How to use this on windows XP(32-bit). Is it possible to implement volume shodow copy in XP? Thanks in advance.
Sorry for the delay.
There are a few caveats that I have found out since writing this post.
The default VSS library that comes with the MS SDK will work with Windows Vista and Windows 7 only.
In order to use the Volume Shadow Copy Services in Windows XP and Windows server 2003, you must download the Volume Shadow Copy Services SDK 7.2and create separate modules for each of the operating systems.
Each module needs to include the appropriate vss.h and linked to the appropriate vssapi.lib. The VSS SDK will include these files in its install directory.
The last thing that you really need to watch out for is that your VSS application must run native 32 or 64-bit, which means if you are running on a 64-bit OS, you must use the APIs in a 64-bit application. This has caused us to get creative and create separate command-line utilities for XP, 2003, Vista/7 32-bit, and Vista/7 64-bit.
Hopefully this helps.