Лучший способ обнаружить вставку DVD в привод С#

Я попытался использовать WMI для обнаружения вставки нового носителя в дисковод, используя следующий код. Но есть ли управляемое решение, такое как использование цикла в фоновом потоке с DriveInfo.GetDrives? Как лучше всего это сделать? Я получаю диалоговое окно «Диск не находится в дисководе, пожалуйста, вставьте диск» с кнопкой «Прервать, повторить попытку и продолжить» на другом компьютере, когда я попробовал следующий код? На майской машине работает нормально.

private void DriveWatcher()
{
    try
    {
        var wqlEventQuery = new WqlEventQuery
            {
                EventClassName = "__InstanceModificationEvent",
                WithinInterval = new TimeSpan(0, 0, 1),
                Condition =
                    @"TargetInstance ISA 'Win32_LogicalDisk' and TargetInstance.DriveType = 5"
            };

        var connectionOptions = new ConnectionOptions
            {
                EnablePrivileges = true,
                Authority = null,
                Authentication = AuthenticationLevel.Default
            };

        var managementScope = new ManagementScope("\\root\\CIMV2", connectionOptions);

        ManagementEventWatcher = new ManagementEventWatcher(managementScope, wqlEventQuery);
        ManagementEventWatcher.EventArrived += CdrEventArrived;
        ManagementEventWatcher.Start();
    }
    catch (ManagementException e)
    {
        MessageBox.Show(e.Message, e.GetType().ToString(), MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
}

private void CdrEventArrived(object sender, EventArrivedEventArgs e)
{
    var wmiDevice = (ManagementBaseObject) e.NewEvent["TargetInstance"];
    if (wmiDevice.Properties["VolumeName"].Value != null)
        GetDrives();
    else
        GetDrives();
}

private void GetDrives()
{
    if (InvokeRequired)
    {
        Invoke(new GetDrivesDelegate(GetDrives));
    }
    else
    {
        toolStripComboBoxDrives.Items.Clear();
        DriveInfo[] drives = DriveInfo.GetDrives();
        _drives = new Dictionary<string, DriveInfo>();
        int selectedIndex = 0;
        foreach (DriveInfo drive in drives)
        {
            if (drive.DriveType.Equals(DriveType.CDRom))
            {
                if (drive.IsReady)
                {
                    string name = string.Format("{0} ({1})", drive.VolumeLabel, drive.Name.Substring(0, 2));
                    int selectedDrive = toolStripComboBoxDrives.Items.Add(name);
                    _drives.Add(name, drive);
                    selectedIndex = selectedDrive;
                }
                else
                {
                    toolStripComboBoxDrives.Items.Add(drive.Name);
                    _drives.Add(drive.Name, drive);
                }
            }
        }
        toolStripComboBoxDrives.SelectedIndex = selectedIndex;
    }
}

В основном то, что я делаю, это событие загрузки формы, называемое Drive Watcher. Поэтому, когда диск вставлен, готовый диск будет указан первым в поле со списком, и пользователь сможет легко извлечь диск.


person Ravi Patel    schedule 25.04.2013    source источник
comment
Вы проверяете машину на базе Windows?   -  person Arshad    schedule 25.04.2013
comment
да, на моем компьютере установлена ​​​​Windows 8, но на другом компьютере установлены Windows 7 и 5 из 1 раза, когда он выдает ошибку, говорящую мне вставить диск.   -  person Ravi Patel    schedule 26.04.2013
comment
ты пробовал с моим ответом   -  person Arshad    schedule 26.04.2013
comment
Собираюсь проверить репозиторий WMI, как вы предложили. Обновите вопрос, когда это будет сделано.   -  person Ravi Patel    schedule 26.04.2013


Ответы (3)


вы можете попробовать с этим кодом:

public void networkDevice()
{
    try
    {
        WqlEventQuery q = new WqlEventQuery();
        q.EventClassName = "__InstanceModificationEvent";
        q.WithinInterval = new TimeSpan(0, 0, 1);
        q.Condition = @"TargetInstance ISA 'Win32_LogicalDisk' and TargetInstance.DriveType = 5";

        ConnectionOptions opt = new ConnectionOptions();
        opt.EnablePrivileges = true;
        opt.Authority = null;
        opt.Authentication = AuthenticationLevel.Default;
        //opt.Username = "Administrator";
        //opt.Password = "";
        ManagementScope scope = new ManagementScope("\\root\\CIMV2", opt);

        ManagementEventWatcher watcher = new ManagementEventWatcher(scope, q);
        watcher.EventArrived += new EventArrivedEventHandler(watcher_EventArrived);
        watcher.Start();
    }
    catch (ManagementException e)
    {
        Console.WriteLine(e.Message);
    }
}

void watcher_EventArrived(object sender, EventArrivedEventArgs e)
{
    ManagementBaseObject wmiDevice = (ManagementBaseObject)e.NewEvent["TargetInstance"];
    string driveName = (string)wmiDevice["DeviceID"];
    Console.WriteLine(driveName);
    Console.WriteLine(wmiDevice.Properties["VolumeName"].Value);
    Console.WriteLine((string)wmiDevice["Name"]);
    if (wmiDevice.Properties["VolumeName"].Value != null)
        Console.WriteLine("CD has been inserted");
    else
        Console.WriteLine("CD has been ejected");
}

если он работает на вашем компьютере и не работает на любом другом компьютере с Windows, вам необходимо перестроить/починить/перерегистрировать классы WMI этой машины. Это поможет вам в этом.

person Arshad    schedule 25.04.2013
comment
Сброс WMI работает. Но я думаю, что управляемое решение окажется лучше, чем использование WMI. - person Ravi Patel; 30.04.2013

См. следующий код:

foreach (DriveInfo drive in DriveInfo.GetDrives().Where(d => d.DriveType == DriveType.CDRom))  
    MessageBox.Show(drive.Name + " " + drive.IsReady.ToString());  

Справочная ссылка:

http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/1ecb74cd-d193-40f5-9aa3-47a3c9adb4ea/

Ссылка на стек:

Определение наличия диска в DVD-приводе

person Freelancer    schedule 25.04.2013

Я собираюсь со следующим решением. Это 100% управляемое решение. Он не использует WMI и прекрасно работает.

internal class DriveWatcher
{
    public delegate void OpticalDiskArrivedEventHandler(Object sender, OpticalDiskArrivedEventArgs e);

    /// <summary>
    ///     Gets or sets the time, in seconds, before the drive watcher checks for new media insertion relative to the last occurance of check.
    /// </summary>
    public int Interval = 1;

    private Timer _driveTimer;

    private Dictionary<string, bool> _drives;

    private bool _haveDisk;

    /// <summary>
    ///     Occurs when a new optical disk is inserted or ejected.
    /// </summary>
    public event OpticalDiskArrivedEventHandler OpticalDiskArrived;

    private void OnOpticalDiskArrived(OpticalDiskArrivedEventArgs e)
    {
        OpticalDiskArrivedEventHandler handler = OpticalDiskArrived;
        if (handler != null) handler(this, e);
    }

    public void Start()
    {
        _drives = new Dictionary<string, bool>();
        foreach (
            DriveInfo drive in
                DriveInfo.GetDrives().Where(driveInfo => driveInfo.DriveType.Equals(DriveType.CDRom)))
        {
            _drives.Add(drive.Name, drive.IsReady);
        }
        _driveTimer = new Timer {Interval = Interval*1000};
        _driveTimer.Elapsed += DriveTimerOnElapsed;
        _driveTimer.Start();
    }

    public void Stop()
    {
        if (_driveTimer != null)
        {
            _driveTimer.Stop();
            _driveTimer.Dispose();
        }
    }

    private void DriveTimerOnElapsed(object sender, ElapsedEventArgs elapsedEventArgs)
    {
        if (!_haveDisk)
        {
            try
            {
                _haveDisk = true;
                foreach (DriveInfo drive in from drive in DriveInfo.GetDrives()
                                            where drive.DriveType.Equals(DriveType.CDRom)
                                            where _drives.ContainsKey(drive.Name)
                                            where !_drives[drive.Name].Equals(drive.IsReady)
                                            select drive)
                {
                    _drives[drive.Name] = drive.IsReady;
                    OnOpticalDiskArrived(new OpticalDiskArrivedEventArgs {Drive = drive});
                }
            }
            catch (Exception exception)
            {
                Debug.Write(exception.Message);
            }
            finally
            {
                _haveDisk = false;
            }
        }
    }
}

internal class OpticalDiskArrivedEventArgs : EventArgs
{
    public DriveInfo Drive;
}

Вы можете использовать это следующим образом.

var driveWatcher = new DriveWatcher();
driveWatcher.OpticalDiskArrived += DriveWatcherOnOpticalDiskArrived;
driveWatcher.Start();

private void DriveWatcherOnOpticalDiskArrived(object sender, OpticalDiskArrivedEventArgs e)
{
    MessageBox.Show(e.Drive.Name);
}
person Ravi Patel    schedule 30.04.2013
comment
Ваш код не работает так, как написано. Не существует класса с именем «DriveSystemWatcher». - person Dan Esparza; 17.09.2013
comment
Вызов обработчика OpticalDiskArrived занимает около 10-12 секунд. Кто-нибудь еще сталкивался с подобной проблемой? - person Ranu Mandan; 24.10.2013
comment
Я использовал этот код в своем приложении. См. rbsoft.org/downloads/easy-disk-catalog-maker. - person Ravi Patel; 25.10.2013
comment
Также вы можете настроить интервал опроса, используя параметр Interval класса DriveWatcher. - person Ravi Patel; 25.10.2013