Detectar cuando la bandeja del lector está abierta o cerrada

Iniciado por Meta, 12 Noviembre 2017, 01:04 AM

0 Miembros y 2 Visitantes están viendo este tema.

Meta

Hola:

Aquí hay un código que pulsando A o C abre o cierras la bandeja del lector, a parte de esto, dice Abierto, Abriendo... Cerrado y Cerrando... Todo esto pulsado las teclas A o C.

Me he dado cuenta que si cierro la bandeja directamente con la mano, en la ventana o en el CMD de C#, no lo sabe, se queda en Abierto. La idea es que si cierro la bandeja con la mano, en la pantalla muestre el mensaje.

¿Esto es posible de hacer?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using static System.Net.Mime.MediaTypeNames;

namespace Lector_teclado_consola_cs
{
    class Program
    {
        [DllImport("winmm.dll")]
        public static extern Int32 mciSendString(string lpstrCommand, StringBuilder lpstrReturnString,
        int uReturnLength, IntPtr hwndCallback);

        public static StringBuilder rt = new StringBuilder(127);

        public static void DoEvents()
        {
            // Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate { }));
            Console.SetCursorPosition(0, 6);
            Console.Write("Abriendo...");
        }

        public static void DoEvents2()
        {
            // Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate { }));
            Console.SetCursorPosition(0, 6);
            Console.Write("Cerrando...");
        }

        static void Main(string[] args)
        {
            // Título de la ventana.
            Console.Title = "Control lector de bandeja.";

            // Tamaño ventana consola.
            Console.WindowWidth = 55; // X. Ancho.
            Console.WindowHeight = 18; // Y. Alto.

            // Cursor invisible.
            Console.CursorVisible = false;

            // Posición del mansaje en la ventana.
            Console.SetCursorPosition(0, 0);
            Console.Write(@"Control bandeja del lector:

A - Abrir bandeja.
C - Cerrar bandeja.
===========================");



            ConsoleKey key;
            //Console.CursorVisible = false;
            do
            {
                key = Console.ReadKey(true).Key;

                string mensaje = string.Empty;

                //Asignamos la tecla presionada por el usuario
                switch (key)
                {
                    case ConsoleKey.A:
                        // mensaje = "Abriendo...";
                        Console.SetCursorPosition(0, 6);
                        DoEvents();
                        mciSendString("set CDAudio door open", rt, 127, IntPtr.Zero);
                        mensaje = "Abierto.";
                        break;

                    case ConsoleKey.C:
                        // mensaje = "Cerrando...";
                        Console.SetCursorPosition(0, 6);
                        DoEvents2();
                        mciSendString("set CDAudio door closed", rt, 127, IntPtr.Zero);
                        mensaje = "Cerrado.";
                        break;
                }

                Console.SetCursorPosition(0, 6);
                Console.Write("           ");
                Console.SetCursorPosition(0, 6);
                Console.Write(mensaje);

            } while (key != ConsoleKey.Escape);
        }
    }
}


Sólo debo modificar o ampliar esa función que falta para dejar el programa más completo.

Saludos.
Tutoriales Electrónica y PIC: http://electronica-pic.blogspot.com/

Eleкtro

#1
Cita de: Meta en 12 Noviembre 2017, 01:04 AMAquí hay un código que pulsando A o C abre o cierras la bandeja del lector, a parte de esto, dice Abierto, Abriendo... Cerrado y Cerrando... Todo esto pulsado las teclas A o C.

Me he dado cuenta que si cierro la bandeja directamente con la mano, en la ventana o en el CMD de C#, no lo sabe, se queda en Abierto. La idea es que si cierro la bandeja con la mano, en la pantalla muestre el mensaje.

¿Esto es posible de hacer?

Tu mismo estás diciendo que lo de "Abriendo..." y "Cerrando..." lo estás imprimiendo por ti mismo cuando pulsas la tecla A o C en la CMD... en ningún momento estás controlando eventos de inserción o eyección de la bandeja del lector, ¿cómo esperas que sea posible hacerlo controlando el input de la CMD?, no tiene sentido xD.

De todas formas MCI solamente sirve para operar con comandos, no es posible detectar/suscribirse a eventos de inserción y eyección de la bandeja del lector de CD-ROM mediante MCI. Pero si con WMI...

Te muestro un ejemplo que escribí hace tiempo en VB.NET y que hace exactamente lo que pides:
Código (vbnet) [Seleccionar]
Imports System.ComponentModel
Imports System.Management

Public NotInheritable Class Form1 : Inherits Form

   Private WithEvents EventWatcher As ManagementEventWatcher

   Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load

       ' https://msdn.microsoft.com/en-us/library/aa394173%28v=vs.85%29.aspx
       Dim eventQuery As New WqlEventQuery(
           eventClassName:="__InstanceModificationEvent",
           condition:="TargetInstance ISA 'Win32_LogicalDisk' AND TargetInstance.DriveType = 5",
           withinInterval:=TimeSpan.FromSeconds(1))

       Dim eventOptions As New EventWatcherOptions With {
           .BlockSize = 1,
           .Timeout = TimeSpan.MaxValue
       }

       Dim scopePath As New ManagementPath With {
           .ClassName = "",
           .NamespacePath = "root\CIMV2",
           .Path = "\\.\root\CIMV2",
           .Server = "."
       }

       Dim scopeOptions As New ConnectionOptions With {
           .Authentication = AuthenticationLevel.Default,
           .EnablePrivileges = True,
           .Impersonation = ImpersonationLevel.Impersonate,
           .Timeout = TimeSpan.MaxValue
       }

       Dim scope As New ManagementScope(scopePath, scopeOptions)

       Me.EventWatcher = New ManagementEventWatcher With {
           .Options = eventOptions,
           .Query = eventQuery,
           .Scope = scope
       }

       Me.EventWatcher.Scope.Connect()
       Me.EventWatcher.Start()

   End Sub

   Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
       Me.EventWatcher.Dispose()
   End Sub

   Private Sub EventWatcher_EventArrived(sender As Object, e As EventArrivedEventArgs) Handles EventWatcher.EventArrived

       Using mo As ManagementBaseObject = e.NewEvent

           Dim letter As String = Convert.ToString(mo.Properties("Name").Value).TrimEnd({":"c, "\"c})
           ' Dim volName As String = Convert.ToString(mo.Properties("VolumeName").Value)

           Dim di As DriveInfo = (From item In DriveInfo.GetDrives()
                                  Where item.Name.TrimEnd({":"c, "\"c}) = letter
                                 ).Single()

           If Not String.IsNullOrEmpty(di.VolumeLabel) Then
               Console.WriteLine(String.Format("CD-ROM tray inserted in drive '{0}'.", di.Name))

           Else
               Console.WriteLine(String.Format("CD-ROM tray ejected in drive '{0}'.", di.Name))

           End If

       End Using

   End Sub

End Class


Traducción a C#:

Código (csharp) [Seleccionar]
using System;
using System.IO;
using System.Linq;
using System.Management;
using System.Windows.Forms;

namespace WindowsFormsApp1 {

   public partial class Form1 : Form {

       private ManagementEventWatcher EventWatcher;

       public Form1() {
           this.InitializeComponent();
       }

       private void Form1_Load(object sender, EventArgs e) {

           // https://msdn.microsoft.com/en-us/library/aa394173%28v=vs.85%29.aspx
           WqlEventQuery eventQuery =
               new WqlEventQuery(eventClassName: "__InstanceModificationEvent",
                                 condition: "TargetInstance ISA 'Win32_LogicalDisk' AND TargetInstance.DriveType = 5",
                                 withinInterval: TimeSpan.FromSeconds(1));

           EventWatcherOptions eventOptions = new EventWatcherOptions {
               BlockSize = 1,
               Timeout = TimeSpan.MaxValue
           };

           ManagementPath scopePath = new ManagementPath {
               ClassName = "",
               NamespacePath = @"root\CIMV2",
               Path = @"\\.\root\CIMV2",
               Server = "."
           };

           ConnectionOptions scopeOptions = new ConnectionOptions {
               Authentication = AuthenticationLevel.Default,
               EnablePrivileges = true,
               Impersonation = ImpersonationLevel.Impersonate,
               Timeout = TimeSpan.MaxValue
           };

           ManagementScope scope = new ManagementScope(scopePath, scopeOptions);

           this.EventWatcher = new ManagementEventWatcher {
               Options = eventOptions,
               Query = eventQuery,
               Scope = scope
           };

           this.EventWatcher.Scope.Connect();
           this.EventWatcher.EventArrived += this.EventWatcher_EventArrived;
           this.EventWatcher.Start();
       }

       private void Form1_FormClosing(object sender, FormClosingEventArgs e) {
           this.EventWatcher.Dispose();
       }

       private void EventWatcher_EventArrived(object sender, EventArrivedEventArgs e) {

           using (ManagementBaseObject mo = e.NewEvent) {

               string letter = Convert.ToString(mo.Properties["Name"].Value).TrimEnd(new char[] {':', '\\'});
               // string volName = Convert.ToString(mo.Properties("VolumeName").Value);

               DriveInfo di = (from item in DriveInfo.GetDrives()
                               where item.Name.TrimEnd(new char[] { ':', '\\' }) == letter
                               select item
                              ).Single();

               if (!string.IsNullOrEmpty(di.VolumeLabel)) {
                   Console.WriteLine(string.Format("CD-ROM tray inserted in drive '{0}'.", di.Name));

               } else {
                   Console.WriteLine(string.Format("CD-ROM tray ejected in drive '{0}'.", di.Name));

               }

           }

       }

   }

}


PD: No lo he testeado, ahora mismo no tengo lector de CD instalado, pero debe funcionar... por que en el pasado me funcionó xD.

PD2: Si en lugar de un Form quieres hacerlo a través de una aplicación de consola, entonces tal vez quieras usar el método bloqueante ManagementEventWatcher.WaitForNextEvent() para que no se cierre la instancia de tu programa antes de recibir el próximo evento...

Código (csharp) [Seleccionar]
...
this.EventWatcher.Start();

while (true) {
    this.EventWatcher.WaitForNextEvent();
}
...


Saludos.








Meta

#2
Hola:

Copié tu código. Errores por todas partes, no respondí antes por ser muy lioso estos errores que pasé.


Gracias por tu tiempo. ;)

MOD: Imagen adaptada a lo permitido. (Ya deberías saber ésto)
Tutoriales Electrónica y PIC: http://electronica-pic.blogspot.com/

okik

#3
hola buenas

Tras leer el comentario de @Elektro en el otro tema(Hacer funcionar el lector de bandeja de discos con este lenguaje .net), decidí entrar aquí a ver el código de @Elektro.

Bueno, a mí tampoco me funcionaba el código de @Elektro pero conseguí que funcionara tras algunos cambios, especialmente con TimeSpan y ManagementBaseObject.

El caso es que ya me funciona y aquí dejo el código (que es un 99% del de @Elektro pero vamos  :P)

Pero antes algunos detalles,
- Desde NET, debe agregarse, desde 'agregar referencia'  la librería System.Management
- La unidad de CD/DVD ROM debe contener un disco en su interior, de lo contrario este código no hace nada de nada.

NOTA: En ambos casos he usado el un proyecto "Aplicación de Windows Forms"

C#
Código (csharp) [Seleccionar]

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Management;
using System.IO;
namespace WindowsFormsApplication1
{
   public partial class Form1 : Form
   {
       public Form1()
       {
           InitializeComponent();
       }
       private ManagementEventWatcher withEventsField_EventWatcher;
       private ManagementEventWatcher EventWatcher
       {
           get { return withEventsField_EventWatcher; }
           set
           {
               if (withEventsField_EventWatcher != null)
               {
                   withEventsField_EventWatcher.EventArrived -= EventWatcher_EventArrived;
               }
               withEventsField_EventWatcher = value;
               if (withEventsField_EventWatcher != null)
               {
                   withEventsField_EventWatcher.EventArrived += EventWatcher_EventArrived;
               }
           }

       }

       private void Form1_FormClosing(object sender, FormClosingEventArgs e)
       {
           this.EventWatcher.Dispose();
       }
       private void Form1_Load(object sender, EventArgs e)
       {
           try
           {
               WqlEventQuery eventQuery = new WqlEventQuery();
               eventQuery.EventClassName = "__InstanceModificationEvent";
               eventQuery.WithinInterval = new TimeSpan(0, 0, 1);
               eventQuery.Condition = "TargetInstance ISA 'Win32_LogicalDisk' and TargetInstance.DriveType = 5";


               EventWatcherOptions eventOptions = new EventWatcherOptions
               {
                   BlockSize = 1,
                   Timeout = TimeSpan.MaxValue
               };

               ManagementPath scopePath = new ManagementPath
               {
                   ClassName = "",
                   NamespacePath = "root\\CIMV2",
                   Path = "\\\\.\\root\\CIMV2",
                   Server = "."
               };

               ConnectionOptions scopeOptions = new ConnectionOptions
               {
                   Authentication = AuthenticationLevel.Default,
                   EnablePrivileges = true,
                   Impersonation = ImpersonationLevel.Impersonate,
                   Timeout = TimeSpan.MaxValue
               };

               ManagementScope scope = new ManagementScope("\\root\\CIMV2", scopeOptions);

               this.EventWatcher = new ManagementEventWatcher
               {
                   Options = eventOptions,
                   Query = eventQuery,
                   Scope = scope
               };

               this.EventWatcher.Scope.Connect();
               this.EventWatcher.Start();
           }
           catch (ManagementException ex)
           {
               Console.WriteLine(ex.Message);
           }
       }
       private void EventWatcher_EventArrived(object sender, EventArrivedEventArgs e)
       {
         ManagementBaseObject wmiDevice = (ManagementBaseObject)e.NewEvent["TargetInstance"];
           string VolumeName = null;
           string driveName = (string)wmiDevice["DeviceID"];
           if (wmiDevice.Properties["VolumeName"].Value != null)
                 {
            VolumeName  = wmiDevice.Properties["VolumeName"].Value.ToString();
                 }
           string Name = (string)wmiDevice["Name"];

           StringBuilder infoMessage = new StringBuilder();
           infoMessage.AppendLine(driveName);
           infoMessage.AppendLine(VolumeName);
           infoMessage.AppendLine(Name);
           if (wmiDevice.Properties["VolumeName"].Value != null)
           {
               infoMessage.AppendLine("CD has been inserted");

           }
           else
           {
               infoMessage.AppendLine("CD has been ejected");

           }
           MessageBox.Show(infoMessage.ToString());
       }
 
   }
}



VB.NET
Código (vbnet) [Seleccionar]


Imports System.Management
Imports System.IO

Public Class Form1
   Private WithEvents EventWatcher As ManagementEventWatcher

   Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing

   End Sub
   Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

       Try
           Dim eventQuery As New WqlEventQuery()
           eventQuery.EventClassName = "__InstanceModificationEvent"
           eventQuery.WithinInterval = New TimeSpan(0, 0, 1)
           eventQuery.Condition = "TargetInstance ISA 'Win32_LogicalDisk' and TargetInstance.DriveType = 5"

         
           Dim eventOptions As New EventWatcherOptions With {
                .BlockSize = 1,
                .Timeout = TimeSpan.MaxValue
            }

           Dim scopePath As New ManagementPath With {
               .ClassName = "",
               .NamespacePath = "root\CIMV2",
               .Path = "\\.\root\CIMV2",
               .Server = "."
           }

           Dim scopeOptions As New ConnectionOptions With {
               .Authentication = AuthenticationLevel.Default,
               .EnablePrivileges = True,
               .Impersonation = ImpersonationLevel.Impersonate,
               .Timeout = TimeSpan.MaxValue
           }

           Dim scope As New ManagementScope("\root\CIMV2", scopeOptions)

           Me.EventWatcher = New ManagementEventWatcher With {
               .Options = eventOptions,
               .Query = EventQuery,
               .Scope = scope
           }

           Me.EventWatcher.Scope.Connect()
           Me.EventWatcher.Start()
       Catch ex As ManagementException
           Console.WriteLine(ex.Message)
       End Try
   End Sub

   Private Sub EventWatcher_EventArrived(sender As Object, e As EventArrivedEventArgs) Handles EventWatcher.EventArrived
         Dim wmiDevice As ManagementBaseObject = DirectCast(e.NewEvent("TargetInstance"), ManagementBaseObject)
       Dim driveName As String = DirectCast(wmiDevice("DeviceID"), String)
       Dim VolumeName As String = wmiDevice.Properties("VolumeName").Value
       Dim Name As String = DirectCast(wmiDevice("Name"), String)

       Dim infoMessage As New StringBuilder
       infoMessage.AppendLine(driveName)
       infoMessage.AppendLine(VolumeName)
       infoMessage.AppendLine(Name)
       If wmiDevice.Properties("VolumeName").Value IsNot Nothing Then
           infoMessage.AppendLine("CD has been inserted")

       Else
           infoMessage.AppendLine("CD has been ejected")

       End If
       MessageBox.Show(infoMessage.ToString)
   End Sub

   Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
       Me.EventWatcher.Dispose()
   End Sub

End Class




Meta

Hola:

Me ejecuta el programa. Como sabrás, no hay botón para abrir y cerrar la bandeja. Así sin más no pasa nada.

Puse un botón y este código en el cual no furula. Xdddd.

Código (csharp) [Seleccionar]
        private void button_Abrir_Click(object sender, EventArgs e)
        {
            EventWatcher_EventArrived();
        }


Saludos.
Tutoriales Electrónica y PIC: http://electronica-pic.blogspot.com/

okik

Cita de: Meta en 18 Noviembre 2017, 01:32 AM
Hola:

Me ejecuta el programa. Como sabrás, no hay botón para abrir y cerrar la bandeja. Así sin más no pasa nada.

Puse un botón y este código en el cual no furula. Xdddd.

Código (csharp) [Seleccionar]
        private void button_Abrir_Click(object sender, EventArgs e)
        {
            EventWatcher_EventArrived();
        }


Saludos.
Hombre así tal cual...

Sería así:
Código (csharp) [Seleccionar]

this.EventWatcher.Start();



He hecho esta emulación de lo que se podría hacer pero el thread debería ejecutarse con load para cambiar el botón Cerrar, Abrir si el usuario abriera o cerrara desde el "eject" del propio lector, además que detecte si hay disco o no.

Código (csharp) [Seleccionar]

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Management;
using System.IO;
using System.Runtime.InteropServices;
namespace WindowsFormsApplication1
{
   public partial class Form1 : Form
   {
       public Form1()
       {
           InitializeComponent();
       }
       private ManagementEventWatcher withEventsField_EventWatcher;
       private ManagementEventWatcher EventWatcher
       {
           get { return withEventsField_EventWatcher; }
           set
           {
               if (withEventsField_EventWatcher != null)
               {
                   withEventsField_EventWatcher.EventArrived -= EventWatcher_EventArrived;
               }
               withEventsField_EventWatcher = value;
               if (withEventsField_EventWatcher != null)
               {
                   withEventsField_EventWatcher.EventArrived += EventWatcher_EventArrived;
               }
           }

       }

       [DllImport("winmm.dll")]
       private static extern uint mciSendString(string sCommand, StringBuilder sReturn, uint cchReturn, IntPtr hwnd);
       bool bolEject = false;
       private void Form1_FormClosing(object sender, FormClosingEventArgs e)

       {
           this.EventWatcher.Dispose();
       }
       private void Form1_Load(object sender, EventArgs e)
       {
           try
           {
               btnEject.Text = "Abrir";
               WqlEventQuery eventQuery = new WqlEventQuery();
               eventQuery.EventClassName = "__InstanceModificationEvent";
               eventQuery.WithinInterval = new TimeSpan(0, 0, 1);
               eventQuery.Condition = "TargetInstance ISA 'Win32_LogicalDisk' and TargetInstance.DriveType = 5";


               EventWatcherOptions eventOptions = new EventWatcherOptions
               {
                   BlockSize = 1,
                   Timeout = TimeSpan.MaxValue
               };

               ManagementPath scopePath = new ManagementPath
               {
                   ClassName = "",
                   NamespacePath = "root\\CIMV2",
                   Path = "\\\\.\\root\\CIMV2",
                   Server = "."
               };

               ConnectionOptions scopeOptions = new ConnectionOptions
               {
                   Authentication = AuthenticationLevel.Default,
                   EnablePrivileges = true,
                   Impersonation = ImpersonationLevel.Impersonate,
                   Timeout = TimeSpan.MaxValue
               };

               ManagementScope scope = new ManagementScope("\\root\\CIMV2", scopeOptions);

               this.EventWatcher = new ManagementEventWatcher
               {
                   Options = eventOptions,
                   Query = eventQuery,
                   Scope = scope
               };

               this.EventWatcher.Scope.Connect();
            //  this.EventWatcher.Start();
           }
           catch (ManagementException ex)
           {
               Console.WriteLine(ex.Message);
           }
       }
       private void EventWatcher_EventArrived(object sender, EventArrivedEventArgs e)
       {
           ManagementBaseObject wmiDevice = (ManagementBaseObject)e.NewEvent["TargetInstance"];
           string VolumeName = null;
           string driveName = (string)wmiDevice["DeviceID"];
           if (wmiDevice.Properties["VolumeName"].Value != null)
                 {
            VolumeName  = wmiDevice.Properties["VolumeName"].Value.ToString();
                 }
           string Name = (string)wmiDevice["Name"];

           StringBuilder infoMessage = new StringBuilder();
           infoMessage.AppendLine(driveName);
           infoMessage.AppendLine(VolumeName);
           infoMessage.AppendLine(Name);
          this.Invoke(new Action(()  =>
           {
               if (wmiDevice.Properties["VolumeName"].Value != null)
               {
                   infoMessage.AppendLine("CD has been inserted");
                   label1.Text = "Cerrado";
                   btnEject.Text = "Abrir";
                   bolEject = false;
               }
               else
               {
                   infoMessage.AppendLine("CD has been ejected");
                   label1.Text = "Abierto";
                   btnEject.Text = "Cerrar";
                   bolEject = true;


               }
               btnEject.Enabled = true;
           }));
           this.EventWatcher.Stop();
           MessageBox.Show(infoMessage.ToString());

       }

       private void btnEject_Click(object sender, EventArgs e)
       {

           IntPtr ptr = IntPtr.Zero;
           StringBuilder returnstring = new StringBuilder();
this.EventWatcher.Start();
if (bolEject == false) {
this.label1.Text = "Abriendo...";
           mciSendString("set CDAudio door open", returnstring, 127, IntPtr.Zero);
         

} else {
           this.label1.Text = "Cerrando...";
           mciSendString("set CDAudio door closed", returnstring, 127, IntPtr.Zero);
}

btnEject.Enabled = false;

       }
 
   }
}