diff --git a/Saviour Backup System/Saviour Backup System.csproj b/Saviour Backup System/Saviour Backup System.csproj
index 6c05cf6..bdc52b4 100644
--- a/Saviour Backup System/Saviour Backup System.csproj
+++ b/Saviour Backup System/Saviour Backup System.csproj
@@ -51,6 +51,7 @@
+
Form
diff --git a/Saviour Backup System/ejectDrive.cs b/Saviour Backup System/ejectDrive.cs
new file mode 100644
index 0000000..535193e
--- /dev/null
+++ b/Saviour Backup System/ejectDrive.cs
@@ -0,0 +1,349 @@
+using System;
+using System.Text;
+using System.Runtime.InteropServices;
+using System.Collections;
+using System.Collections.Generic;
+using System.Threading;
+using System.ComponentModel;
+
+namespace Saviour_Backup_System
+{
+
+ public class RemoveDriveTools //Taken from: http://www.codeproject.com/Articles/375916/How-to-Prepare-a-USB-Drive-for-Safe-Removal
+ {
+ [StructLayout(LayoutKind.Sequential)]
+ struct STORAGE_DEVICE_NUMBER
+ {
+ public int DeviceType;
+ public int DeviceNumber;
+ public int PartitionNumber;
+ };
+
+ enum DriveType : uint
+ {
+ /// The drive type cannot be determined.
+ DRIVE_UNKNOWN = 0, //DRIVE_UNKNOWN
+ /// The root path is invalid, for example, no volume is mounted at the path.
+ DRIVE_NO_ROOT_DIR = 1, //DRIVE_NO_ROOT_DIR
+ /// The drive is a type that has removable media, for example, a floppy drive or removable hard disk.
+ DRIVE_REMOVABLE = 2, //DRIVE_REMOVABLE
+ /// The drive is a type that cannot be removed, for example, a fixed hard drive.
+ DRIVE_FIXED = 3, //DRIVE_FIXED
+ /// The drive is a remote (network) drive.
+ DRIVE_REMOTE = 4, //DRIVE_REMOTE
+ /// The drive is a CD-ROM drive.
+ DRIVE_CDROM = 5, //DRIVE_CDROM
+ /// The drive is a RAM disk.
+ DRIVE_RAMDISK = 6 //DRIVE_RAMDISK
+ }
+
+ const string GUID_DEVINTERFACE_VOLUME = "53f5630d-b6bf-11d0-94f2-00a0c91efb8b";
+ const string GUID_DEVINTERFACE_DISK = "53f56307-b6bf-11d0-94f2-00a0c91efb8b";
+ const string GUID_DEVINTERFACE_FLOPPY = "53f56311-b6bf-11d0-94f2-00a0c91efb8b";
+ const string GUID_DEVINTERFACE_CDROM = "53f56308-b6bf-11d0-94f2-00a0c91efb8b";
+
+ const int INVALID_HANDLE_VALUE = -1;
+ const int GENERIC_READ = unchecked((int)0x80000000);
+ const int GENERIC_WRITE = unchecked((int)0x40000000);
+ const int FILE_SHARE_READ = unchecked((int)0x00000001);
+ const int FILE_SHARE_WRITE = unchecked((int)0x00000002);
+ const int OPEN_EXISTING = unchecked((int)3);
+ const int FSCTL_LOCK_VOLUME = unchecked((int)0x00090018);
+ const int FSCTL_DISMOUNT_VOLUME = unchecked((int)0x00090020);
+ const int IOCTL_STORAGE_EJECT_MEDIA = unchecked((int)0x002D4808);
+ const int IOCTL_STORAGE_MEDIA_REMOVAL = unchecked((int)0x002D4804);
+ const int IOCTL_STORAGE_GET_DEVICE_NUMBER = unchecked((int)0x002D1080);
+
+ const int ERROR_NO_MORE_ITEMS = 259;
+ const int ERROR_INSUFFICIENT_BUFFER = 122;
+ const int ERROR_INVALID_DATA = 13;
+
+ [DllImport("kernel32.dll")]
+ static extern DriveType GetDriveType([MarshalAs(UnmanagedType.LPStr)] string lpRootPathName);
+
+ [DllImport("kernel32.dll")]
+ static extern uint QueryDosDevice(string lpDeviceName, StringBuilder lpTargetPath, int ucchMax);
+
+ [DllImport("kernel32.dll", EntryPoint = "CreateFileW", CharSet = CharSet.Unicode, SetLastError = true)]
+ static extern IntPtr CreateFile(
+ string lpFileName,
+ int dwDesiredAccess,
+ int dwShareMode,
+ IntPtr lpSecurityAttributes,
+ int dwCreationDisposition,
+ int dwFlagsAndAttributes,
+ IntPtr hTemplateFile);
+
+ [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)]
+ static extern bool CloseHandle(IntPtr handle);
+
+ [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)]
+ static extern bool DeviceIoControl(
+ IntPtr hDevice,
+ int dwIoControlCode,
+ IntPtr lpInBuffer,
+ int nInBufferSize,
+ IntPtr lpOutBuffer,
+ int nOutBufferSize,
+ out int lpBytesReturned,
+ IntPtr lpOverlapped);
+
+ // from setupapi.h
+ const int DIGCF_PRESENT = (0x00000002);
+ const int DIGCF_DEVICEINTERFACE = (0x00000010);
+
+ [StructLayout(LayoutKind.Sequential)]
+ class SP_DEVINFO_DATA
+ {
+ public int cbSize = Marshal.SizeOf(typeof(SP_DEVINFO_DATA));
+ public Guid classGuid = Guid.Empty; // temp
+ public int devInst = 0; // dumy
+ public int reserved = 0;
+ }
+
+ [StructLayout(LayoutKind.Sequential, Pack = 2)]
+ struct SP_DEVICE_INTERFACE_DETAIL_DATA
+ {
+ public int cbSize;
+ public short devicePath;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ class SP_DEVICE_INTERFACE_DATA
+ {
+ public int cbSize = Marshal.SizeOf(typeof(SP_DEVICE_INTERFACE_DATA));
+ public Guid interfaceClassGuid = Guid.Empty; // temp
+ public int flags = 0;
+ public int reserved = 0;
+ }
+
+ [DllImport("setupapi.dll")]
+ static extern IntPtr SetupDiGetClassDevs(
+ ref Guid classGuid,
+ int enumerator,
+ IntPtr hwndParent,
+ int flags);
+
+ [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ static extern bool SetupDiEnumDeviceInterfaces(
+ IntPtr deviceInfoSet,
+ SP_DEVINFO_DATA deviceInfoData,
+ ref Guid interfaceClassGuid,
+ int memberIndex,
+ SP_DEVICE_INTERFACE_DATA deviceInterfaceData);
+
+ [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ static extern bool SetupDiGetDeviceInterfaceDetail(
+ IntPtr deviceInfoSet,
+ SP_DEVICE_INTERFACE_DATA deviceInterfaceData,
+ IntPtr deviceInterfaceDetailData,
+ int deviceInterfaceDetailDataSize,
+ ref int requiredSize,
+ SP_DEVINFO_DATA deviceInfoData);
+
+ [DllImport("setupapi.dll")]
+ static extern uint SetupDiDestroyDeviceInfoList(
+ IntPtr deviceInfoSet);
+
+ [DllImport("setupapi.dll")]
+ static extern int CM_Get_Parent(
+ ref int pdnDevInst,
+ int dnDevInst,
+ int ulFlags);
+
+ [DllImport("setupapi.dll")]
+ static extern int CM_Request_Device_Eject(
+ int dnDevInst,
+ out PNP_VETO_TYPE pVetoType,
+ StringBuilder pszVetoName,
+ int ulNameLength,
+ int ulFlags);
+
+ [DllImport("setupapi.dll", EntryPoint = "CM_Request_Device_Eject")]
+ static extern int CM_Request_Device_Eject_NoUi(
+ int dnDevInst,
+ IntPtr pVetoType,
+ StringBuilder pszVetoName,
+ int ulNameLength,
+ int ulFlags);
+
+ enum PNP_VETO_TYPE
+ {
+ Ok,
+ TypeUnknown,
+ LegacyDevice,
+ PendingClose,
+ WindowsApp,
+ WindowsService,
+ OutstandingOpen,
+ Device,
+ Driver,
+ IllegalDeviceRequest,
+ InsufficientPower,
+ NonDisableable,
+ LegacyDriver,
+ InsufficientRights
+ }
+
+ ///
+ /// Call with "X:" or similar
+ ///
+ ///
+ ///
+ public static bool RemoveDrive(string driveCharWithColon)
+ {
+ // open the storage volume
+ IntPtr hVolume = CreateFile(@"\\.\" + driveCharWithColon, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);
+ if (hVolume.ToInt32() == -1) return false;
+
+ // get the volume's device number
+ long DeviceNumber = GetDeviceNumber(hVolume);
+ if (DeviceNumber == -1) return false;
+
+ // get the drive type which is required to match the device numbers correctely
+ string rootPath = driveCharWithColon + "\\";
+ DriveType driveType = GetDriveType(rootPath);
+
+ // get the dos device name (like \device\floppy0) to decide if it's a floppy or not - who knows a better way?
+ StringBuilder pathInformation = new StringBuilder(250);
+ uint res = QueryDosDevice(driveCharWithColon, pathInformation, 250);
+ if (res == 0) return false;
+
+ // get the device instance handle of the storage volume by means of a SetupDi enum and matching the device number
+ long DevInst = GetDrivesDevInstByDeviceNumber(DeviceNumber, driveType, pathInformation.ToString());
+ if (DevInst == 0) return false;
+
+ // get drives's parent, e.g. the USB bridge, the SATA port, an IDE channel with two drives!
+ int DevInstParent = 0;
+ CM_Get_Parent(ref DevInstParent, (int)DevInst, 0);
+
+ for (int tries = 1; tries <= 3; tries++) // sometimes we need some tries...
+ {
+ int r = CM_Request_Device_Eject_NoUi(DevInstParent, IntPtr.Zero, null, 0, 0);
+ if (r == 0) return true;
+ Thread.Sleep(500);
+ }
+ return false;
+ }
+
+ static long GetDeviceNumber(IntPtr handle)
+ {
+ // get the volume's device number
+ long DeviceNumber = -1;
+ int size = 0x400; // some big size
+ IntPtr buffer = Marshal.AllocHGlobal(size);
+ int bytesReturned = 0;
+
+ try
+ {
+ DeviceIoControl(handle, IOCTL_STORAGE_GET_DEVICE_NUMBER, IntPtr.Zero, 0, buffer, size, out bytesReturned, IntPtr.Zero);
+ }
+ finally
+ {
+ CloseHandle(handle);
+ }
+
+ if (bytesReturned > 0)
+ {
+ STORAGE_DEVICE_NUMBER sdn = (STORAGE_DEVICE_NUMBER)Marshal.PtrToStructure(buffer, typeof(STORAGE_DEVICE_NUMBER));
+ DeviceNumber = sdn.DeviceNumber;
+ }
+ Marshal.FreeHGlobal(buffer);
+
+ return DeviceNumber;
+ }
+
+
+ //----------------------------------------------------------------------
+ // returns the device instance handle of a storage volume or 0 on error
+ //----------------------------------------------------------------------
+ static long GetDrivesDevInstByDeviceNumber(long DeviceNumber, DriveType DriveType, string dosDeviceName)
+ {
+ bool IsFloppy = dosDeviceName.Contains("\\Floppy"); // who knows a better way?
+ Guid guid;
+
+ switch (DriveType)
+ {
+ case DriveType.DRIVE_REMOVABLE:
+ if (IsFloppy) guid = new Guid(GUID_DEVINTERFACE_FLOPPY);
+ else guid = new Guid(GUID_DEVINTERFACE_DISK);
+ break;
+ case DriveType.DRIVE_FIXED:
+ guid = new Guid(GUID_DEVINTERFACE_DISK);
+ break;
+ case DriveType.DRIVE_CDROM:
+ guid = new Guid(GUID_DEVINTERFACE_CDROM);
+ break;
+ default:
+ return 0;
+ }
+
+ // Get device interface info set handle for all devices attached to system
+ IntPtr hDevInfo = SetupDiGetClassDevs(ref guid, 0, IntPtr.Zero, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
+
+ if (hDevInfo.ToInt32() == INVALID_HANDLE_VALUE) throw new Win32Exception(Marshal.GetLastWin32Error());
+
+ // Retrieve a context structure for a device interface of a device information set
+ int dwIndex = 0;
+
+ while (true)
+ {
+ SP_DEVICE_INTERFACE_DATA interfaceData = new SP_DEVICE_INTERFACE_DATA();
+ if (!SetupDiEnumDeviceInterfaces(hDevInfo, null, ref guid, dwIndex, interfaceData))
+ {
+ int error = Marshal.GetLastWin32Error();
+ if (error != ERROR_NO_MORE_ITEMS) throw new Win32Exception(error);
+ break;
+ }
+
+ SP_DEVINFO_DATA devData = new SP_DEVINFO_DATA();
+ int size = 0;
+ if (!SetupDiGetDeviceInterfaceDetail(hDevInfo, interfaceData, IntPtr.Zero, 0, ref size, devData))
+ {
+ int error = Marshal.GetLastWin32Error();
+ if (error != ERROR_INSUFFICIENT_BUFFER) throw new Win32Exception(error);
+ }
+
+ IntPtr buffer = Marshal.AllocHGlobal(size);
+ SP_DEVICE_INTERFACE_DETAIL_DATA detailData = new SP_DEVICE_INTERFACE_DETAIL_DATA();
+ detailData.cbSize = Marshal.SizeOf(typeof(SP_DEVICE_INTERFACE_DETAIL_DATA));
+ Marshal.StructureToPtr(detailData, buffer, false);
+
+ if (!SetupDiGetDeviceInterfaceDetail(hDevInfo, interfaceData, buffer, size, ref size, devData))
+ {
+ Marshal.FreeHGlobal(buffer);
+ throw new Win32Exception(Marshal.GetLastWin32Error());
+ }
+
+ IntPtr pDevicePath = (IntPtr)((int)buffer + Marshal.SizeOf(typeof(int)));
+ string devicePath = Marshal.PtrToStringAuto(pDevicePath);
+ Marshal.FreeHGlobal(buffer);
+
+ // open the disk or cdrom or floppy
+ IntPtr hDrive = CreateFile(devicePath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);
+ if (hDrive.ToInt32() != INVALID_HANDLE_VALUE)
+ {
+ // get its device number
+ long driveDeviceNumber = GetDeviceNumber(hDrive);
+ if (DeviceNumber == driveDeviceNumber) // match the given device number with the one of the current device
+ {
+ // CloseHandle( hDrive ); // handle hDrive was closed inside GetDeviceNumber(..)
+ SetupDiDestroyDeviceInfoList(hDevInfo);
+ return devData.devInst;
+ }
+ // CloseHandle( hDrive ); // handle hDrive was closed inside GetDeviceNumber(..)
+
+ }
+ dwIndex++;
+ }
+
+ SetupDiDestroyDeviceInfoList(hDevInfo);
+ return 0;
+ }
+
+ static void Test()
+ {
+ bool ok = RemoveDrive("H:");
+ }
+ }
+}