Para los aficionados al desarrollo de aplicaciones con .NET y C#, aquí voy a dejar un trozo de código muy interesante.
Básicamente consiste en un método para notificar a una aplicación de que se ha insertado un nuevo disco en el sistema (un CD, DVD, llave USB, tarjeta de memoria SD/MMC/etc, Disco duro externo, …), un método para identificar la letra de la nueva unidad, y a partir de ellos construir las aplicaciones que se nos ocurran que puedan aprovecharse de esta funcionalidad.
//Incluir esto es obligatorio
using System.Runtime.InteropServices;
/*
* Escribe aquí el código de tu programa (¡O donde prefieras!)…
*/
//Estructura de datos que almacena la gestión de conexiones
[StructLayout(LayoutKind.Sequential)]
public struct DEV_BROADCAST_VOLUME
{
public int dbcv_size;
public int dbcv_devicetype;
public int dbcv_reserved;
public int dbcv_unitmask;
}
//Método a sobreescribir para gestionar la llegada de nuevas unidades de disco
protected override void WndProc(ref Message m)
{
//Estas definiciones están en dbt.h y winuser.h
//Se ha producido un cambio en los dispositivos
const int WM_DEVICECHANGE = 0×0219;
// El sistema detecta un nuevo dispositivo
const int DBT_DEVICEARRIVAL = 0×8000;
//Solicita retirada del dispositivo
const int DBT_DEVICEQUERYREMOVE = 0×8001;
//Ha fallado la retirada del dispositivo
const int DBT_DEVICEQUERYREMOVEFAILED = 0×8002;
//Pendiente extracción del dispositivo
const int DBT_DEVICEREMOVEPENDING = 0×8003;
//Dispositivo extraído del sistema
const int DBT_DEVICEREMOVECOMPLETE = 0×8004;
// Volumen lógico (Se ha insertado un disco)
const int DBT_DEVTYP_VOLUME = 0×00000002;
switch (m.Msg)
{
//Cambian los dispositivos del sistema
case WM_DEVICECHANGE:
switch (m.WParam.ToInt32())
{
//Llegada de un dispositivo
case DBT_DEVICEARRIVAL:
{
int devType = Marshal.ReadInt32(m.LParam, 4);
//Si es un volumen lógico..(unidad de disco)
if (devType == DBT_DEVTYP_VOLUME)
{
DEV_BROADCAST_VOLUME vol;
vol = (DEV_BROADCAST_VOLUME)Marshal.PtrToStructure(
m.LParam, typeof(DEV_BROADCAST_VOLUME));
MessageBox.Show(
”Insertada unida de disco, unidad: ” +
LetraUnidad(vol.dbcv_unitmask));
}
}
break;
case DBT_DEVICEREMOVECOMPLETE:
MessageBox.Show(”Dispositivo retirado.”);
break;
}
break;
}
//Ahora usar el manejador predeterminado
base.WndProc(ref m);
}
//Método para detectar la letra de unidad
char LetraUnidad(int unitmask)
{
char[] units ={ ‘A’, ‘B’, ‘C’, ‘D’, ‘E’, ‘F’, ‘G’,
’H', ‘I’, ‘J’, ‘K’, ‘L’, ‘M’, ‘N’, ‘O’, ‘P’,
’Q', ‘R’, ‘S’, ‘T’, ‘U’, ‘V’, ‘W’, ‘X’, ‘Y’, ‘Z’ };
int i = 0;
//Convetimos la máscara en un array primario y buscamos
//el índice de la primera ocurrencia (la letra de unidad)
System.Collections.BitArray ba = new
System.Collections.BitArray(System.BitConverter.GetBytes(unitmask));
foreach (bool var in ba)
{
if (var == true)
break;
i++;
}
return units[i];
}
Aquí os dejo (correctamente formateada) la aportación de Carolina, el código en Visual Basic para la detección de unidades:
‘Estructura de datos que almacena la gestión de conexiones
Public Structure dispositivo
Public dispTamaño As Integer
Public dispTipo As Integer
Public dispReserv As Integer
Public dispMask As Integer
End Structure
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
‘Se ha producido un cambio en los dispositivos
Const deviceChange As Integer = &H219
‘El sistema detecta un nuevo dispositivo
Const deviceArrival As Integer = &H8000
‘Solicita retirada del dispositivo
Const deviceQueryRemove As Integer = &H8001
‘Ha fallado la retirada del dispositivo
Const devideQueryRemoveFailed As Integer = &H8002
‘Pendiente extracción del dispositivo
Const deviceRemovePending As Integer = &H8003
‘Dispositivo extraído del sistema
Const deviceRemoveComplete As Integer = &H8004
‘ Volumen lógico (Se ha insertado un disco)
Const deviceTypeVolume As Integer = &H2
Select Case m.Msg
‘Cambian los dispositivos del sistema
Case deviceChange
Select Case m.WParam.ToInt32
‘Llegada de un dispositivo
Case deviceArrival
Dim devType As Integer = Marshal.ReadInt32(m.LParam, 4)
‘Si es un volumen lógico..(unidad de disco)
If devType = deviceTypeVolume Then
Dim vol As dispositivo
vol = CType(Marshal.PtrToStructure(m.LParam, GetType(dispositivo)), dispositivo)
MessageBox.Show(”Se insertó un dispositivo en la unidad ” & LetraUnidad(vol.dispMask) & “.”)
‘ACA HAGO EL TRATAMIENTO DEL DISPOSITIVO INSERTADO
End If
Case deviceRemoveComplete
MessageBox.Show(”Se retiró el dispositivo.”)
End Select
End Select
‘Ahora se usa el manejador predeterminado
MyBase.WndProc(m)
End Sub
Private Function LetraUnidad(ByVal unitmask As Integer) As Char
Dim units() As Char = {”A”, “B”, “C”, “D”, “E”, “F”, “G”,
“H”, “I”, “J”, “K”, “L”, “M”, “N”, “O”, “P”,
“Q”, “R”, “S”, “T”, “U”, “V”, “W”, “X”, “Y”, “Z”}
Dim i As Integer = 0
‘Convetimos la máscara en un array primario y buscamos
‘el índice de la primera ocurrencia (la letra de unidad)
Dim ba As System.Collections.BitArray
ba = New System.Collections.BitArray(System.BitConverter.GetBytes(unitmask))
For i = 0 To ba.Length
If ba(i) = True Then
Exit For
End If
Next
Return units(i)
End Function



Miércoles, 24 Octubre, 2007 a las 9:09 pm
Hola quisiera saber realmente como compilar ese codigo, lenjuage y tipo de aplicacion, o en que parte del codigo se debe incluir
parece un buen proyecto y te agradeceria
Miércoles, 24 Octubre, 2007 a las 9:16 pm
¡Pues incluirlo es lo más sencillo del mundo!
Crea un proyecto Windows.Forms (Lenguaje C#) cualquiera y a continuación pega el trozo de código tal cual, justo debajo del grupo de líneas using.
Eso sobreescribe el manejador de la ventana con la función grande del snippet. Básicamente, hace lo mismo que el manejador predeterminado, además de mostrar un mensaje diciendo que se ha insertado una unidad de disco. Como por defecto no se sabía qué unidad era, incluí la función auxiliar LetraUnidad para poder acceder más rápido a la ruta de acceso estándar.
Jueves, 25 Octubre, 2007 a las 4:34 am
Ya ejecute el codigo y si funciona
EL problema es que solo me funciona para memorias usb y discos compactos
pero no me funciona para tarjetas de memoria al menos en este equipo
Jueves, 3 Enero, 2008 a las 5:31 pm
Que tal !!! Quisiera saber si hay una forma de que este mismo
codigo sirviera para una aplicacion en consola, ya que ahi no acepta
la palabra ” Message “,
por otra parte gracias por el codigo.
Martes, 15 Enero, 2008 a las 11:39 am
Perdona el retraso en la respuesta.
Para una aplicación de consola no puedes usar el método MessageBox.Show(“Mensajito de texto”) porque es exclusivo de aplicaciones winForms. Para ello necesitas incluir las winforms escribiendo using System.Windows.Forms;, o bien cambiar el MessageBox.Show por un equivalente en modo texto como System.Console.WriteLine(“TextoAEscribir”);
Miércoles, 25 Junio, 2008 a las 10:03 pm
Gracias, por el código. Funciona de maravilla, pero ¿habría alguna forma de saber que dispositivos USB tengo conectados si necesidad de conectarlos después de iniciar el programa?
Gracias.
Miércoles, 25 Junio, 2008 a las 10:26 pm
¡Buena pregunta! En éste código me he centrado en la detección de los eventos de inserción de dispositivo, pero no he investigado cómo ver los dispositivos que ya hay conectados (aunque mi instinto me dice que es bastante más sencillo que este snippet).
Jueves, 26 Junio, 2008 a las 6:28 am
Excelente aporte!! No sabe cuanto tiempo anduve buscando un código como este! Desde ya se lo agradezco mucho. Abusando un poco de su bondad, podria decirme como hacer lo mismo pero en Visual Basic 2005 ?? Muchas gracias por adelantado.
Jueves, 26 Junio, 2008 a las 8:20 am
Me temo que Visual Basic no es mi especialidad… (¡Lo siento mucho!)
PD: Gracias a todos por vuestros comentarios
Jueves, 26 Junio, 2008 a las 5:57 pm
Ohh lastima!, bueno igual muchas gracias por responder. Abusando nuevamente de su buena volundad, podría Enviarme a mi email un proyecto de C# con este código implementado correctamente?. Lo que sucede es que C# no es mi especialidad (como lo habrá podido notar en mi nick jejeje), entonces me salen algunos errores al compilar el código (hice paso a paso lo que indicaba usted en un mensaje anterior, uso Visual Studio 2005). Mi correo es luisito666(arroba)gmail.com Se lo agradecería infinitamente.
Domingo, 14 Septiembre, 2008 a las 9:50 pm
Hola, yo pude pasar a VB el codigo que publico Antonius (en C#) y me anduvo muy bien. Ademas de agradecer su aporte, queria dejarles el mio para los que necesiten:
‘Estructura de datos que almacena la gestión de conexiones
Public Structure dispositivo
Public dispTamaño As Integer
Public dispTipo As Integer
Public dispReserv As Integer
Public dispMask As Integer
End Structure
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
‘Se ha producido un cambio en los dispositivos
Const deviceChange As Integer = &H219
‘El sistema detecta un nuevo dispositivo
Const deviceArrival As Integer = &H8000
‘Solicita retirada del dispositivo
Const deviceQueryRemove As Integer = &H8001
‘Ha fallado la retirada del dispositivo
Const devideQueryRemoveFailed As Integer = &H8002
‘Pendiente extracción del dispositivo
Const deviceRemovePending As Integer = &H8003
‘Dispositivo extraído del sistema
Const deviceRemoveComplete As Integer = &H8004
‘ Volumen lógico (Se ha insertado un disco)
Const deviceTypeVolume As Integer = &H2
Select Case m.Msg
‘Cambian los dispositivos del sistema
Case deviceChange
Select Case m.WParam.ToInt32
‘Llegada de un dispositivo
Case deviceArrival
Dim devType As Integer = Marshal.ReadInt32(m.LParam, 4)
‘Si es un volumen lógico..(unidad de disco)
If devType = deviceTypeVolume Then
Dim vol As dispositivo
vol = CType(Marshal.PtrToStructure(m.LParam, GetType(dispositivo)), dispositivo)
MessageBox.Show(“Se insertó un dispositivo en la unidad ” & LetraUnidad(vol.dispMask) & “.”)
‘ACA HAGO EL TRATAMIENTO DEL DISPOSITIVO INSERTADO
End If
Case deviceRemoveComplete
MessageBox.Show(“Se retiró el dispositivo.”)
End Select
End Select
‘Ahora se usa el manejador predeterminado
MyBase.WndProc(m)
End Sub
Private Function LetraUnidad(ByVal unitmask As Integer) As Char
Dim units() As Char = {“A”, “B”, “C”, “D”, “E”, “F”, “G”, “H”, “I”, “J”, “K”, “L”, “M”, “N”, “O”, “P”, “Q”, “R”, “S”, “T”, “U”, “V”, “W”, “X”, “Y”, “Z”}
Dim i As Integer = 0
‘Convetimos la máscara en un array primario y buscamos
‘el índice de la primera ocurrencia (la letra de unidad)
Dim ba As System.Collections.BitArray
ba = New System.Collections.BitArray(System.BitConverter.GetBytes(unitmask))
For i = 0 To ba.Length
If ba(i) = True Then
Exit For
End If
Next
Return units(i)
End Function
Domingo, 14 Septiembre, 2008 a las 9:58 pm
Muchas gracias por tu aporte! (En cuanto tenga algo de tiempo intentaré darle el formato tipo código y añadirlo al post).
Me alegra mucho que este pequeño trozo de código le sea útil a tantas personas, y espero que tu aportación ayude a muchas otras.
Gracias!
Lunes, 15 Septiembre, 2008 a las 8:56 pm
Excelente!! muchas gracias
Viernes, 19 Septiembre, 2008 a las 7:47 pm
Hola, tengo una duda en esta parte del códgio de vb
Dim devType As Integer = Marshal.ReadInt32(m.LParam, 4)
me subraya la parte de “Marshal”, qué es lo que debo de hacer ahí
Gracias
Viernes, 19 Septiembre, 2008 a las 9:06 pm
El Marshal lo que hace es convertir una lectura de datos de memoria “insegura” a memoria “manejada”(segura) para poder usarlos desde .NET sin que haya problemas.
Más información aquí: http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal(VS.80).aspx
Viernes, 24 Octubre, 2008 a las 6:39 am
Hola, exelente aporte ese pedaso de código,¿sabes cómo podría hacerlo con C/C++?
Domingo, 26 Octubre, 2008 a las 9:38 pm
Hola, me descarge ya el Microsoft Visual C# 2005 Express para tratar de implementar tu código, pero me da bastantes errores, no sé que es lo que este haciendo mal. No conosco mucho C#, tengo experiencia programando aplicaciones para consola en lenguaje C. Seria mucha molestia que pudieras enviarme el proyecto a mi correo? gracias de antemano.
jorgeriv@gmail.com
Viernes, 8 Mayo, 2009 a las 9:47 pm
muy buen codigo la vdd