diff --git a/DiskImager/Detection/DriveDetector.cs b/DiskImager/Detection/DriveDetector.cs
new file mode 100644
index 0000000..642aac0
--- /dev/null
+++ b/DiskImager/Detection/DriveDetector.cs
@@ -0,0 +1,812 @@
+using System;
+using System.Windows.Forms; // required for Message
+using System.Runtime.InteropServices; // required for Marshal
+using System.IO;
+using Microsoft.Win32.SafeHandles;
+
+namespace DynamicDevices.DiskWriter.Detection
+{
+ ///
+ /// Hidden Form which we use to receive Windows messages about flash drives
+ ///
+ internal class DetectorForm : Form
+ {
+ private Label label1;
+ private DriveDetector mDetector = null;
+
+ ///
+ /// Set up the hidden form.
+ ///
+ /// DriveDetector object which will receive notification about USB drives, see WndProc
+ public DetectorForm(DriveDetector detector)
+ {
+ mDetector = detector;
+ this.MinimizeBox = false;
+ this.MaximizeBox = false;
+ this.ShowInTaskbar = false;
+ this.ShowIcon = false;
+ this.FormBorderStyle = FormBorderStyle.None;
+ this.Load += new System.EventHandler(this.Load_Form);
+ this.Activated += new EventHandler(this.Form_Activated);
+ }
+
+ private void Load_Form(object sender, EventArgs e)
+ {
+ // We don't really need this, just to display the label in designer ...
+ InitializeComponent();
+
+ // Create really small form, invisible anyway.
+ this.Size = new System.Drawing.Size(5, 5);
+ }
+
+ private void Form_Activated(object sender, EventArgs e)
+ {
+ this.Visible = false;
+ }
+
+ ///
+ /// This function receives all the windows messages for this window (form).
+ /// We call the DriveDetector from here so that is can pick up the messages about
+ /// drives arrived and removed.
+ ///
+ protected override void WndProc(ref Message m)
+ {
+ base.WndProc(ref m);
+
+ if (mDetector != null)
+ {
+ mDetector.WndProc(ref m);
+ }
+ }
+
+ private void InitializeComponent()
+ {
+ this.label1 = new System.Windows.Forms.Label();
+ this.SuspendLayout();
+ //
+ // label1
+ //
+ this.label1.AutoSize = true;
+ this.label1.Location = new System.Drawing.Point(13, 30);
+ this.label1.Name = "label1";
+ this.label1.Size = new System.Drawing.Size(314, 13);
+ this.label1.TabIndex = 0;
+ this.label1.Text = "This is invisible form. To see DriveDetector code click View Code";
+ //
+ // DetectorForm
+ //
+ this.ClientSize = new System.Drawing.Size(360, 80);
+ this.Controls.Add(this.label1);
+ this.Name = "DetectorForm";
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+ } // class DetectorForm
+
+
+ // Delegate for event handler to handle the device events
+ public delegate void DriveDetectorEventHandler(Object sender, DriveDetectorEventArgs e);
+
+ ///
+ /// Our class for passing in custom arguments to our event handlers
+ ///
+ ///
+ public class DriveDetectorEventArgs : EventArgs
+ {
+
+
+ public DriveDetectorEventArgs()
+ {
+ Cancel = false;
+ Drive = "";
+ HookQueryRemove = false;
+ }
+
+ ///
+ /// Get/Set the value indicating that the event should be cancelled
+ /// Only in QueryRemove handler.
+ ///
+ public bool Cancel;
+
+ ///
+ /// Drive letter for the device which caused this event
+ ///
+ public string Drive;
+
+ ///
+ /// Set to true in your DeviceArrived event handler if you wish to receive the
+ /// QueryRemove event for this drive.
+ ///
+ public bool HookQueryRemove;
+
+ }
+
+
+ ///
+ /// Detects insertion or removal of removable drives.
+ /// Use it in 1 or 2 steps:
+ /// 1) Create instance of this class in your project and add handlers for the
+ /// DeviceArrived, DeviceRemoved and QueryRemove events.
+ /// AND (if you do not want drive detector to creaate a hidden form))
+ /// 2) Override WndProc in your form and call DriveDetector's WndProc from there.
+ /// If you do not want to do step 2, just use the DriveDetector constructor without arguments and
+ /// it will create its own invisible form to receive messages from Windows.
+ ///
+ class DriveDetector : IDisposable
+ {
+ ///
+ /// Events signalized to the client app.
+ /// Add handlers for these events in your form to be notified of removable device events
+ ///
+ public event DriveDetectorEventHandler DeviceArrived;
+ public event DriveDetectorEventHandler DeviceRemoved;
+ public event DriveDetectorEventHandler QueryRemove;
+
+ ///
+ /// The easiest way to use DriveDetector.
+ /// It will create hidden form for processing Windows messages about USB drives
+ /// You do not need to override WndProc in your form.
+ ///
+ public DriveDetector()
+ {
+ DetectorForm frm = new DetectorForm(this);
+ frm.Show(); // will be hidden immediatelly
+ Init(frm, null);
+ }
+
+ ///
+ /// Alternate constructor.
+ /// Pass in your Form and DriveDetector will not create hidden form.
+ ///
+ /// object which will receive Windows messages.
+ /// Pass "this" as this argument from your form class.
+ public DriveDetector(Control control)
+ {
+ Init(control, null);
+ }
+
+ ///
+ /// Consructs DriveDetector object setting also path to file which should be opened
+ /// when registering for query remove.
+ ///
+ ///object which will receive Windows messages.
+ /// Pass "this" as this argument from your form class.
+ /// Optional. Name of a file on the removable drive which should be opened.
+ /// If null, root directory of the drive will be opened. Opening a file is needed for us
+ /// to be able to register for the query remove message. TIP: For files use relative path without drive letter.
+ /// e.g. "SomeFolder\file_on_flash.txt"
+ public DriveDetector(Control control, string FileToOpen)
+ {
+ Init(control, FileToOpen);
+ }
+
+ ///
+ /// init the DriveDetector object
+ ///
+ ///
+ private void Init(Control control, string fileToOpen)
+ {
+ mFileToOpen = fileToOpen;
+ mFileOnFlash = null;
+ mDeviceNotifyHandle = IntPtr.Zero;
+ mRecipientHandle = control.Handle;
+ mDirHandle = IntPtr.Zero; // handle to the root directory of the flash drive which we open
+ mCurrentDrive = "";
+ }
+
+ ///
+ /// Gets the value indicating whether the query remove event will be fired.
+ ///
+ public bool IsQueryHooked
+ {
+ get
+ {
+ if (mDeviceNotifyHandle == IntPtr.Zero)
+ return false;
+ else
+ return true;
+ }
+ }
+
+ ///
+ /// Gets letter of drive which is currently hooked. Empty string if none.
+ /// See also IsQueryHooked.
+ ///
+ public string HookedDrive
+ {
+ get
+ {
+ return mCurrentDrive;
+ }
+ }
+
+ ///
+ /// Gets the file stream for file which this class opened on a drive to be notified
+ /// about it's removal.
+ /// This will be null unless you specified a file to open (DriveDetector opens root directory of the flash drive)
+ ///
+ public FileStream OpenedFile
+ {
+ get
+ {
+ return mFileOnFlash;
+ }
+ }
+
+ ///
+ /// Hooks specified drive to receive a message when it is being removed.
+ /// This can be achieved also by setting e.HookQueryRemove to true in your
+ /// DeviceArrived event handler.
+ /// By default DriveDetector will open the root directory of the flash drive to obtain notification handle
+ /// from Windows (to learn when the drive is about to be removed).
+ ///
+ /// Drive letter or relative path to a file on the drive which should be
+ /// used to get a handle - required for registering to receive query remove messages.
+ /// If only drive letter is specified (e.g. "D:\\", root directory of the drive will be opened.
+ /// true if hooked ok, false otherwise
+ public bool EnableQueryRemove(string fileOnDrive)
+ {
+ if (fileOnDrive == null || fileOnDrive.Length == 0)
+ throw new ArgumentException("Drive path must be supplied to register for Query remove.");
+
+ if ( fileOnDrive.Length == 2 && fileOnDrive[1] == ':' )
+ fileOnDrive += '\\'; // append "\\" if only drive letter with ":" was passed in.
+
+ if (mDeviceNotifyHandle != IntPtr.Zero)
+ {
+ // Unregister first...
+ RegisterForDeviceChange(false, null);
+ }
+
+ if (Path.GetFileName(fileOnDrive).Length == 0 ||!File.Exists(fileOnDrive))
+ mFileToOpen = null; // use root directory...
+ else
+ mFileToOpen = fileOnDrive;
+
+ RegisterQuery(Path.GetPathRoot(fileOnDrive));
+ if (mDeviceNotifyHandle == IntPtr.Zero)
+ return false; // failed to register
+
+ return true;
+ }
+
+ ///
+ /// Unhooks any currently hooked drive so that the query remove
+ /// message is not generated for it.
+ ///
+ public void DisableQueryRemove()
+ {
+ if (mDeviceNotifyHandle != IntPtr.Zero)
+ {
+ RegisterForDeviceChange(false, null);
+ }
+ }
+
+
+ ///
+ /// Unregister and close the file we may have opened on the removable drive.
+ /// Garbage collector will call this method.
+ ///
+ public void Dispose()
+ {
+ RegisterForDeviceChange(false, null);
+ }
+
+
+ #region WindowProc
+ ///
+ /// Message handler which must be called from client form.
+ /// Processes Windows messages and calls event handlers.
+ ///
+ ///
+ public void WndProc(ref Message m)
+ {
+ int devType;
+ char c;
+
+ if (m.Msg == WM_DEVICECHANGE)
+ {
+ // WM_DEVICECHANGE can have several meanings depending on the WParam value...
+ switch (m.WParam.ToInt32())
+ {
+
+ //
+ // New device has just arrived
+ //
+ case DBT_DEVICEARRIVAL:
+
+ devType = Marshal.ReadInt32(m.LParam, 4);
+ if (devType == DBT_DEVTYP_VOLUME)
+ {
+ DEV_BROADCAST_VOLUME vol;
+ vol = (DEV_BROADCAST_VOLUME)
+ Marshal.PtrToStructure(m.LParam, typeof(DEV_BROADCAST_VOLUME));
+
+ // Get the drive letter
+ c = DriveMaskToLetter(vol.dbcv_unitmask);
+
+
+ //
+ // Call the client event handler
+ //
+ // We should create copy of the event before testing it and
+ // calling the delegate - if any
+ DriveDetectorEventHandler tempDeviceArrived = DeviceArrived;
+ if ( tempDeviceArrived != null )
+ {
+ DriveDetectorEventArgs e = new DriveDetectorEventArgs();
+ e.Drive = c + ":\\";
+ tempDeviceArrived(this, e);
+
+ // Register for query remove if requested
+ if (e.HookQueryRemove)
+ {
+ // If something is already hooked, unhook it now
+ if (mDeviceNotifyHandle != IntPtr.Zero)
+ {
+ RegisterForDeviceChange(false, null);
+ }
+
+ RegisterQuery(c + ":\\");
+ }
+ } // if has event handler
+
+
+ }
+ break;
+
+
+
+ //
+ // Device is about to be removed
+ // Any application can cancel the removal
+ //
+ case DBT_DEVICEQUERYREMOVE:
+
+ devType = Marshal.ReadInt32(m.LParam, 4);
+ if (devType == DBT_DEVTYP_HANDLE)
+ {
+ // TODO: we could get the handle for which this message is sent
+ // from vol.dbch_handle and compare it against a list of handles for
+ // which we have registered the query remove message (?)
+ //DEV_BROADCAST_HANDLE vol;
+ //vol = (DEV_BROADCAST_HANDLE)
+ // Marshal.PtrToStructure(m.LParam, typeof(DEV_BROADCAST_HANDLE));
+ // if ( vol.dbch_handle ....
+
+
+ //
+ // Call the event handler in client
+ //
+ DriveDetectorEventHandler tempQuery = QueryRemove;
+ if (tempQuery != null)
+ {
+ DriveDetectorEventArgs e = new DriveDetectorEventArgs();
+ e.Drive = mCurrentDrive; // drive which is hooked
+ tempQuery(this, e);
+
+ // If the client wants to cancel, let Windows know
+ if (e.Cancel)
+ {
+ m.Result = (IntPtr)BROADCAST_QUERY_DENY;
+ }
+ else
+ {
+ // Change 28.10.2007: Unregister the notification, this will
+ // close the handle to file or root directory also.
+ // We have to close it anyway to allow the removal so
+ // even if some other app cancels the removal we would not know about it...
+ RegisterForDeviceChange(false, null); // will also close the mFileOnFlash
+ }
+
+ }
+ }
+ break;
+
+
+ //
+ // Device has been removed
+ //
+ case DBT_DEVICEREMOVECOMPLETE:
+
+ devType = Marshal.ReadInt32(m.LParam, 4);
+ if (devType == DBT_DEVTYP_VOLUME)
+ {
+ devType = Marshal.ReadInt32(m.LParam, 4);
+ if (devType == DBT_DEVTYP_VOLUME)
+ {
+ DEV_BROADCAST_VOLUME vol;
+ vol = (DEV_BROADCAST_VOLUME)
+ Marshal.PtrToStructure(m.LParam, typeof(DEV_BROADCAST_VOLUME));
+ c = DriveMaskToLetter(vol.dbcv_unitmask);
+
+ //
+ // Call the client event handler
+ //
+ DriveDetectorEventHandler tempDeviceRemoved = DeviceRemoved;
+ if (tempDeviceRemoved != null)
+ {
+ DriveDetectorEventArgs e = new DriveDetectorEventArgs();
+ e.Drive = c + ":\\";
+ tempDeviceRemoved(this, e);
+ }
+
+ // TODO: we could unregister the notify handle here if we knew it is the
+ // right drive which has been just removed
+ //RegisterForDeviceChange(false, null);
+ }
+ }
+ break;
+ }
+
+ }
+
+ }
+ #endregion
+
+
+
+ #region Private Area
+
+ ///
+ /// New: 28.10.2007 - handle to root directory of flash drive which is opened
+ /// for device notification
+ ///
+ private IntPtr mDirHandle = IntPtr.Zero;
+
+ ///
+ /// Class which contains also handle to the file opened on the flash drive
+ ///
+ private FileStream mFileOnFlash = null;
+
+ ///
+ /// Name of the file to try to open on the removable drive for query remove registration
+ ///
+ private string mFileToOpen;
+
+ ///
+ /// Handle to file which we keep opened on the drive if query remove message is required by the client
+ ///
+ private IntPtr mDeviceNotifyHandle;
+
+ ///
+ /// Handle of the window which receives messages from Windows. This will be a form.
+ ///
+ private IntPtr mRecipientHandle;
+
+ ///
+ /// Drive which is currently hooked for query remove
+ ///
+ private string mCurrentDrive;
+
+
+ // Win32 constants
+ private const int DBT_DEVTYP_DEVICEINTERFACE = 5;
+ private const int DBT_DEVTYP_HANDLE = 6;
+ private const int BROADCAST_QUERY_DENY = 0x424D5144;
+ private const int WM_DEVICECHANGE = 0x0219;
+ private const int DBT_DEVICEARRIVAL = 0x8000; // system detected a new device
+ private const int DBT_DEVICEQUERYREMOVE = 0x8001; // Preparing to remove (any program can disable the removal)
+ private const int DBT_DEVICEREMOVECOMPLETE = 0x8004; // removed
+ private const int DBT_DEVTYP_VOLUME = 0x00000002; // drive type is logical volume
+
+ ///
+ /// Registers for receiving the query remove message for a given drive.
+ /// We need to open a handle on that drive and register with this handle.
+ /// Client can specify this file in mFileToOpen or we will open root directory of the drive
+ ///
+ /// drive for which to register.
+ private void RegisterQuery(string drive)
+ {
+ bool register = true;
+
+ if (mFileToOpen == null)
+ {
+ // Change 28.10.2007 - Open the root directory if no file specified - leave mFileToOpen null
+ // If client gave us no file, let's pick one on the drive...
+ //mFileToOpen = GetAnyFile(drive);
+ //if (mFileToOpen.Length == 0)
+ // return; // no file found on the flash drive
+ }
+ else
+ {
+ // Make sure the path in mFileToOpen contains valid drive
+ // If there is a drive letter in the path, it may be different from the actual
+ // letter assigned to the drive now. We will cut it off and merge the actual drive
+ // with the rest of the path.
+ if (mFileToOpen.Contains(":"))
+ {
+ string tmp = mFileToOpen.Substring(3);
+ string root = Path.GetPathRoot(drive);
+ mFileToOpen = Path.Combine(root, tmp);
+ }
+ else
+ mFileToOpen = Path.Combine(drive, mFileToOpen);
+ }
+
+
+ try
+ {
+ //mFileOnFlash = new FileStream(mFileToOpen, FileMode.Open);
+ // Change 28.10.2007 - Open the root directory
+ if (mFileToOpen == null) // open root directory
+ mFileOnFlash = null;
+ else
+ mFileOnFlash = new FileStream(mFileToOpen, FileMode.Open);
+ }
+ catch (Exception)
+ {
+ // just do not register if the file could not be opened
+ register = false;
+ }
+
+
+ if (register)
+ {
+ //RegisterForDeviceChange(true, mFileOnFlash.SafeFileHandle);
+ //mCurrentDrive = drive;
+ // Change 28.10.2007 - Open the root directory
+ if (mFileOnFlash == null)
+ RegisterForDeviceChange(drive);
+ else
+ // old version
+ RegisterForDeviceChange(true, mFileOnFlash.SafeFileHandle);
+
+ mCurrentDrive = drive;
+ }
+
+
+ }
+
+
+ ///
+ /// New version which gets the handle automatically for specified directory
+ /// Only for registering! Unregister with the old version of this function...
+ ///
+ ///
+ /// e.g. C:\\dir
+ private void RegisterForDeviceChange(string dirPath)
+ {
+ IntPtr handle = Native.OpenDirectory(dirPath);
+ if (handle == IntPtr.Zero)
+ {
+ mDeviceNotifyHandle = IntPtr.Zero;
+ return;
+ }
+ else
+ mDirHandle = handle; // save handle for closing it when unregistering
+
+ // Register for handle
+ DEV_BROADCAST_HANDLE data = new DEV_BROADCAST_HANDLE();
+ data.dbch_devicetype = DBT_DEVTYP_HANDLE;
+ data.dbch_reserved = 0;
+ data.dbch_nameoffset = 0;
+ //data.dbch_data = null;
+ //data.dbch_eventguid = 0;
+ data.dbch_handle = handle;
+ data.dbch_hdevnotify = (IntPtr)0;
+ int size = Marshal.SizeOf(data);
+ data.dbch_size = size;
+ IntPtr buffer = Marshal.AllocHGlobal(size);
+ Marshal.StructureToPtr(data, buffer, true);
+
+ mDeviceNotifyHandle = Native.RegisterDeviceNotification(mRecipientHandle, buffer, 0);
+
+ }
+
+ ///
+ /// Registers to be notified when the volume is about to be removed
+ /// This is requierd if you want to get the QUERY REMOVE messages
+ ///
+ /// true to register, false to unregister
+ /// handle of a file opened on the removable drive
+ private void RegisterForDeviceChange(bool register, SafeFileHandle fileHandle)
+ {
+ if (register)
+ {
+ // Register for handle
+ DEV_BROADCAST_HANDLE data = new DEV_BROADCAST_HANDLE();
+ data.dbch_devicetype = DBT_DEVTYP_HANDLE;
+ data.dbch_reserved = 0;
+ data.dbch_nameoffset = 0;
+ //data.dbch_data = null;
+ //data.dbch_eventguid = 0;
+ data.dbch_handle = fileHandle.DangerousGetHandle(); //Marshal. fileHandle;
+ data.dbch_hdevnotify = (IntPtr)0;
+ int size = Marshal.SizeOf(data);
+ data.dbch_size = size;
+ IntPtr buffer = Marshal.AllocHGlobal(size);
+ Marshal.StructureToPtr(data, buffer, true);
+
+ mDeviceNotifyHandle = Native.RegisterDeviceNotification(mRecipientHandle, buffer, 0);
+ }
+ else
+ {
+ // close the directory handle
+ if (mDirHandle != IntPtr.Zero)
+ {
+ Native.CloseDirectoryHandle(mDirHandle);
+ // string er = Marshal.GetLastWin32Error().ToString();
+ }
+
+ // unregister
+ if (mDeviceNotifyHandle != IntPtr.Zero)
+ {
+ Native.UnregisterDeviceNotification(mDeviceNotifyHandle);
+ }
+
+
+ mDeviceNotifyHandle = IntPtr.Zero;
+ mDirHandle = IntPtr.Zero;
+
+ mCurrentDrive = "";
+ if (mFileOnFlash != null)
+ {
+ mFileOnFlash.Close();
+ mFileOnFlash = null;
+ }
+ }
+
+ }
+
+ ///
+ /// Gets drive letter from a bit mask where bit 0 = A, bit 1 = B etc.
+ /// There can actually be more than one drive in the mask but we
+ /// just use the last one in this case.
+ ///
+ ///
+ ///
+ private static char DriveMaskToLetter(int mask)
+ {
+ char letter;
+ string drives = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ // 1 = A
+ // 2 = B
+ // 4 = C...
+ int cnt = 0;
+ int pom = mask / 2;
+ while (pom != 0)
+ {
+ // while there is any bit set in the mask
+ // shift it to the righ...
+ pom = pom / 2;
+ cnt++;
+ }
+
+ if (cnt < drives.Length)
+ letter = drives[cnt];
+ else
+ letter = '?';
+
+ return letter;
+ }
+
+ /* 28.10.2007 - no longer needed
+ ///
+ /// Searches for any file in a given path and returns its full path
+ ///
+ /// drive to search
+ /// path of the file or empty string
+ private string GetAnyFile(string drive)
+ {
+ string file = "";
+ // First try files in the root
+ string[] files = Directory.GetFiles(drive);
+ if (files.Length == 0)
+ {
+ // if no file in the root, search whole drive
+ files = Directory.GetFiles(drive, "*.*", SearchOption.AllDirectories);
+ }
+
+ if (files.Length > 0)
+ file = files[0]; // get the first file
+
+ // return empty string if no file found
+ return file;
+ }*/
+ #endregion
+
+
+ #region Native Win32 API
+ ///
+ /// WinAPI functions
+ ///
+ private class Native
+ {
+ // HDEVNOTIFY RegisterDeviceNotification(HANDLE hRecipient,LPVOID NotificationFilter,DWORD Flags);
+ [DllImport("user32.dll", CharSet = CharSet.Auto)]
+ public static extern IntPtr RegisterDeviceNotification(IntPtr hRecipient, IntPtr NotificationFilter, uint Flags);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto)]
+ public static extern uint UnregisterDeviceNotification(IntPtr hHandle);
+
+ //
+ // CreateFile - MSDN
+ const uint GENERIC_READ = 0x80000000;
+ const uint OPEN_EXISTING = 3;
+ const uint FILE_SHARE_READ = 0x00000001;
+ const uint FILE_SHARE_WRITE = 0x00000002;
+ const uint FILE_ATTRIBUTE_NORMAL = 128;
+ const uint FILE_FLAG_BACKUP_SEMANTICS = 0x02000000;
+ static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
+
+
+ // should be "static extern unsafe"
+ [DllImport("kernel32", SetLastError = true)]
+ static extern IntPtr CreateFile(
+ string FileName, // file name
+ uint DesiredAccess, // access mode
+ uint ShareMode, // share mode
+ uint SecurityAttributes, // Security Attributes
+ uint CreationDisposition, // how to create
+ uint FlagsAndAttributes, // file attributes
+ int hTemplateFile // handle to template file
+ );
+
+
+ [DllImport("kernel32", SetLastError = true)]
+ static extern bool CloseHandle(
+ IntPtr hObject // handle to object
+ );
+
+ ///
+ /// Opens a directory, returns it's handle or zero.
+ ///
+ /// path to the directory, e.g. "C:\\dir"
+ /// handle to the directory. Close it with CloseHandle().
+ static public IntPtr OpenDirectory(string dirPath)
+ {
+ // open the existing file for reading
+ IntPtr handle = CreateFile(
+ dirPath,
+ GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ 0,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_NORMAL,
+ 0);
+
+ if ( handle == INVALID_HANDLE_VALUE)
+ return IntPtr.Zero;
+ else
+ return handle;
+ }
+
+
+ public static bool CloseDirectoryHandle(IntPtr handle)
+ {
+ return CloseHandle(handle);
+ }
+ }
+
+
+ // Structure with information for RegisterDeviceNotification.
+ [StructLayout(LayoutKind.Sequential)]
+ public struct DEV_BROADCAST_HANDLE
+ {
+ public int dbch_size;
+ public int dbch_devicetype;
+ public int dbch_reserved;
+ public IntPtr dbch_handle;
+ public IntPtr dbch_hdevnotify;
+ public Guid dbch_eventguid;
+ public long dbch_nameoffset;
+ //public byte[] dbch_data[1]; // = new byte[1];
+ public byte dbch_data;
+ public byte dbch_data1;
+ }
+
+ // Struct for parameters of the WM_DEVICECHANGE message
+ [StructLayout(LayoutKind.Sequential)]
+ public struct DEV_BROADCAST_VOLUME
+ {
+ public int dbcv_size;
+ public int dbcv_devicetype;
+ public int dbcv_reserved;
+ public int dbcv_unitmask;
+ }
+ #endregion
+
+ }
+}
diff --git a/DiskImager/DiskImager.csproj b/DiskImager/DiskImager.csproj
index 6dab5c8..29c5d14 100644
--- a/DiskImager/DiskImager.csproj
+++ b/DiskImager/DiskImager.csproj
@@ -81,6 +81,9 @@
+
+ Form
+
diff --git a/DiskImager/IDiskAccess.cs b/DiskImager/IDiskAccess.cs
index b4aa948..45afb07 100644
--- a/DiskImager/IDiskAccess.cs
+++ b/DiskImager/IDiskAccess.cs
@@ -8,12 +8,6 @@ namespace DynamicDevices.DiskWriter
event ProgressHandler OnProgress;
- event EventHandler OnDiskChanged;
-
- bool StartListenForChanges();
-
- void StopListenForChanges();
-
Handle Open(string drivePath);
bool LockDrive(string drivePath);
diff --git a/DiskImager/MainForm.cs b/DiskImager/MainForm.cs
index b612c36..8a56e91 100644
--- a/DiskImager/MainForm.cs
+++ b/DiskImager/MainForm.cs
@@ -2,6 +2,7 @@
using System.IO;
using System.Reflection;
using System.Windows.Forms;
+using DynamicDevices.DiskWriter.Detection;
using DynamicDevices.DiskWriter.Win32;
using Microsoft.Win32;
@@ -13,6 +14,7 @@ namespace DynamicDevices.DiskWriter
private readonly Disk _disk;
private readonly IDiskAccess _diskAccess;
+ private DriveDetector _watcher = new DriveDetector();
private EnumCompressionType _eCompType;
@@ -79,8 +81,9 @@ namespace DynamicDevices.DiskWriter
_disk.OnProgress += _disk_OnProgress;
// Detect insertions / removals
- _diskAccess.StartListenForChanges();
- _diskAccess.OnDiskChanged += WatcherEventArrived;
+ _watcher.DeviceArrived += OnDriveArrived;
+ _watcher.DeviceRemoved += OnDriveRemoved;
+ StartListenForChanges();
}
#endregion
@@ -211,7 +214,9 @@ namespace DynamicDevices.DiskWriter
key.Close();
}
- _diskAccess.StopListenForChanges();
+ _watcher.DeviceArrived -= OnDriveArrived;
+ _watcher.DeviceRemoved -= OnDriveRemoved;
+ StopListenForChanges();
}
///
@@ -392,5 +397,34 @@ namespace DynamicDevices.DiskWriter
#endregion
+ #region Disk Change Handling
+
+ public bool StartListenForChanges()
+ {
+ _watcher.DeviceArrived += OnDriveArrived;
+ _watcher.DeviceRemoved += OnDriveRemoved;
+ return true;
+ }
+
+ public void StopListenForChanges()
+ {
+ if (_watcher != null)
+ {
+ _watcher.Dispose();
+ _watcher = null;
+ }
+ }
+
+ void OnDriveArrived(object sender, DriveDetectorEventArgs e)
+ {
+ WatcherEventArrived(sender, e);
+ }
+
+ void OnDriveRemoved(object sender, DriveDetectorEventArgs e)
+ {
+ WatcherEventArrived(sender, e);
+ }
+
+ #endregion
}
}
diff --git a/DiskImager/Win32/LinuxDiskAccess.cs b/DiskImager/Win32/LinuxDiskAccess.cs
index cc00bc5..b427368 100644
--- a/DiskImager/Win32/LinuxDiskAccess.cs
+++ b/DiskImager/Win32/LinuxDiskAccess.cs
@@ -13,18 +13,6 @@ namespace DynamicDevices.DiskWriter.Win32
public event ProgressHandler OnProgress;
- public event EventHandler OnDiskChanged;
-
- public bool StartListenForChanges()
- {
- throw new NotImplementedException();
- }
-
- public void StopListenForChanges()
- {
- throw new NotImplementedException();
- }
-
public Handle Open(string drivePath)
{
throw new NotImplementedException();
diff --git a/DiskImager/Win32/Win32DiskAccess.cs b/DiskImager/Win32/Win32DiskAccess.cs
index bccb258..748fcf1 100644
--- a/DiskImager/Win32/Win32DiskAccess.cs
+++ b/DiskImager/Win32/Win32DiskAccess.cs
@@ -1,7 +1,8 @@
using System;
-using System.Linq;
using System.Management;
+using System.Linq;
using System.Runtime.InteropServices;
+using DynamicDevices.DiskWriter.Detection;
using Microsoft.Win32.SafeHandles;
namespace DynamicDevices.DiskWriter.Win32
@@ -12,7 +13,6 @@ namespace DynamicDevices.DiskWriter.Win32
SafeFileHandle _partitionHandle = null;
SafeFileHandle _diskHandle = null;
- ManagementEventWatcher _watcher = new ManagementEventWatcher();
#endregion
@@ -24,30 +24,6 @@ namespace DynamicDevices.DiskWriter.Win32
public event EventHandler OnDiskChanged;
- public bool StartListenForChanges()
- {
- var query = new WqlEventQuery("SELECT * FROM Win32_VolumeChangeEvent WHERE EventType = 2 OR EventType = 3");
- _watcher.EventArrived += WatcherEventArrived;
- _watcher.Query = query;
- _watcher.Start();
- return true;
- }
-
- public void StopListenForChanges()
- {
- if(_watcher != null)
- {
- _watcher.Stop();
- _watcher = null;
- }
- }
-
- void WatcherEventArrived(object sender, EventArrivedEventArgs e)
- {
- if(OnDiskChanged != null)
- OnDiskChanged(sender, e);
- }
-
public Handle Open(string drivePath)
{
int intOut;
@@ -166,6 +142,8 @@ namespace DynamicDevices.DiskWriter.Win32
{
int diskIndex = -1;
+ // todo: For Mono support we need to remove accesses to System.Management namespace
+
logicalPath = logicalPath.Trim(new[] {'\\'});
var scope = new ManagementScope(@"\root\cimv2");