Mark S. Rasmussen improve.dk
Jun 21
2011

When working on OrcaMDF I usually setup a test database, force a checkpoint and then perform my tests on the MDF file. Problem is, you can’t open the MDF file for reading, nor copy it, as long as the database is online in SQL Server. I could shut down SQL Server temporarily while copying the file, but that quickly becomes quite a hassle.

Leveraging Volume Shadow Copy (VSS) through AlphaVSS

AlphaVSS is an excellent library for invoking VSS through .NET. While it can do much more, I’m using it to create a snapshot of a single active file, copy it and then dispose of the snapshot afterwards.

The following class presents a single static method that’ll copy any file (locked or not) and copy it to the desired destination. It would be easy to adapt upon this sample to copy multiple files, directories, etc. Note that while a copy file progress clalback is supported, I don’t really care about the progress and am there sending a null reference when calling CopyFileEx.aspx).

class VssHelper
{
	[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
	private static extern bool CopyFileEx(string lpExistingFileName, string lpNewFileName, CopyProgressRoutine lpProgressRoutine, int lpData, ref int pbCancel, uint dwCopyFlags);
	private delegate uint CopyProgressRoutine(long TotalFileSize, long TotalBytesTransferred, long StreamSize, long StreamBytesTransferred, uint dwStreamNumber, uint dwCallbackReason, IntPtr hSourceFile, IntPtr hDestinationFile, IntPtr lpData);

	public static void CopyFile(string source, string destination)
	{
		var oVSSImpl = VssUtils.LoadImplementation();

		using (var vss = oVSSImpl.CreateVssBackupComponents())
		{
			vss.InitializeForBackup(null);

			vss.SetBackupState(false, true, VssBackupType.Full, false);

			using (var async = vss.GatherWriterMetadata())
				async.Wait();

			vss.StartSnapshotSet();
			string volume = new FileInfo(source).Directory.Root.Name;
			var snapshot = vss.AddToSnapshotSet(volume, Guid.Empty);

			using (var async = vss.PrepareForBackup())
				async.Wait();

			using (var async = vss.DoSnapshotSet())
				async.Wait();

			var props = vss.GetSnapshotProperties(snapshot);
			string vssFile = source.Replace(volume, props.SnapshotDeviceObject + @"");

			int cancel = 0;
			CopyFileEx(vssFile, destination, null, 0, ref cancel, 0);
		}
	}
}
Mark S. Rasmussen
I'm the CTO at iPaper where I cuddle with databases, mold code and maintain the overall technical & team responsibility. I'm an avid speaker at user groups & conferences. I love life, motorcycles, photography and all things technical. Say hi on Twitter, write me an email or look me up on LinkedIn.