I have a class that has a property of type DriveInfo, which has a boolean property of IsReady as you might already know. This is a value representing when the drive is "ready" - for me, that means that there's a CD in the drive, as I've chosen only CDRom drives.
What I would like to do is call an event when the property is updated - currently I'm instantiating the object, then performing a while loop to wait for the value to be true.
public bool WaitUntilReady()
{
while (!Cancelled)
{
if (Drive.IsReady) return true;
}
return false;
}
I'd much prefer a method, or something similar. Thank you.
If you're waiting for changes in device state such as CD insertion/ removal, listening to WM_DEVICECHANGE
message would be a better way.
Windows sends all top-level windows a set of default
WM_DEVICECHANGE
messages when new devices or media (such as a CD or DVD) are added and become available, and when existing devices or media are removed... Read More
Try using the following helper class to listen for media insertion/ removal:
DriveHelper
public static class DriveHelper
{
const int WM_DEVICECHANGE = 0x0219;
const int DBT_DEVICEARRIVAL = 0x8000;
const int DBT_DEVICEREMOVECOMPLETE = 0x8004;
const int DBT_DEVTYP_VOLUME = 0x00000002;
const ushort DBTF_MEDIA = 0x0001;
[StructLayout(LayoutKind.Sequential)]
struct DEV_BROADCAST_VOLUME
{
public uint dbch_Size;
public uint dbch_Devicetype;
public uint dbch_Reserved;
public uint dbch_Unitmask;
public ushort dbch_Flags;
}
public class StateChangedEventArgs : EventArgs
{
public StateChangedEventArgs(string drive, bool ready)
{
Drive = drive;
Ready = ready;
}
public string Drive { get; private set; }
public bool Ready { get; private set; }
}
public static void QueryDeviceChange(Message m, Action<StateChangedEventArgs> action)
{
if (action == null || m.Msg != WM_DEVICECHANGE) return;
var devType = Marshal.ReadInt32(m.LParam, 4);
if (devType != DBT_DEVTYP_VOLUME) return;
var lpdbv = (DEV_BROADCAST_VOLUME)Marshal.PtrToStructure(m.LParam, typeof(DEV_BROADCAST_VOLUME));
if (lpdbv.dbch_Flags != DBTF_MEDIA) return;
var eventCode = m.WParam.ToInt32();
var drive = GetFirstDriveFromMask(lpdbv.dbch_Unitmask);
switch (eventCode)
{
case DBT_DEVICEARRIVAL:
action(new StateChangedEventArgs(drive, true));
break;
case DBT_DEVICEREMOVECOMPLETE:
action(new StateChangedEventArgs(drive, false));
break;
}
}
static string GetFirstDriveFromMask(uint mask)
{
int i;
for (i = 0; i < 26; ++i)
{
if ((mask & 0x1) == 0x1)
break;
mask = mask >> 1;
}
return string.Concat((char)(i + 65), @":\");
}
}
Usage Example (for Windows Forms
apps)
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
void OnStateChanged(DriveHelper.StateChangedEventArgs e)
{
// do your work here
MessageBox.Show(string.Format("Drive: {0} => e.Ready: {1}, DriveInfo.IsReady: {2}", e.Drive, e.Ready, new DriveInfo(e.Drive).IsReady));
}
protected override void WndProc(ref Message m)
{
DriveHelper.QueryDeviceChange(m, OnStateChanged);
base.WndProc(ref m);
}
}