windows - setup - winapi tutorial
Expulsar CDROM de Windows (5)
¿Alguien sabe un método para cerrar programáticamente la bandeja de CD en Windows 2000 o superior? La bandeja de CD abierta existe, pero parece que no puedo cerrarla especialmente bajo W2k.
Estoy especialmente buscando un método para hacer esto desde un archivo por lotes, si es posible, pero las llamadas API estarían bien.
Aquí hay una manera fácil de usar la API de Win32:
[DllImport("winmm.dll", EntryPoint = "mciSendStringA", CharSet = CharSet.Ansi)]
protected static extern int mciSendString(string lpstrCommand,StringBuilder lpstrReturnString,int uReturnLength,IntPtr hwndCallback);
public void OpenCloseCD(bool Open)
{
if (Open)
{
mciSendString("set cdaudio door open", null, 0, IntPtr.Zero);
}
else
{
mciSendString("set cdaudio door closed", null, 0, IntPtr.Zero);
}
}
Nircmd es una utilidad de línea de comandos freeware muy práctica con varias opciones, incluida la apertura y el cierre de la bandeja de CD.
Noté que la respuesta de Andreas Magnusson no funcionaba exactamente igual que el botón de expulsión de Explorer. Específicamente, el disco no estaba atenuado en el Explorador utilizando el código de Andreas, pero lo era si usaba el comando Expulsar. Así que investigué un poco.
Ejecuté el API Monitor mientras ejecutaba el comando Expulsar desde el Explorador (Windows 7 SP1 de 64 bits). También encontré un buen artículo de MSKB 165721 titulado Cómo expulsar medios extraíbles en Windows NT / Windows 2000 / Windows XP . La parte más interesante del artículo de MSKB se cita a continuación:
- Llame a CreateFile con GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, y OPEN_EXISTING. El parámetro lpFileName debe ser /. / X: (donde X es la letra de unidad real). Todos los demás parámetros pueden ser cero.
- Bloquee el volumen emitiendo FSCTL_LOCK_VOLUME IOCTL a través de DeviceIoControl. Si alguna otra aplicación o el sistema está utilizando el volumen, este IOCTL falla. Una vez que esta función regresa con éxito, la aplicación tiene garantizado que el volumen no será utilizado por ninguna otra cosa en el sistema.
- Desmonte el volumen emitiendo FSCTL_DISMOUNT_VOLUME IOCTL. Esto hace que el sistema de archivos elimine todo el conocimiento del volumen y descarte cualquier información interna que guarde con respecto al volumen.
- Asegúrese de que los medios se puedan eliminar emitiendo IOCTL_STORAGE_MEDIA_REMOVAL IOCTL. Establezca el miembro PreventMediaRemoval de la estructura PREVENT_MEDIA_REMOVAL en FALSE antes de llamar a este IOCTL. Esto evita que el dispositivo evite la eliminación de los medios.
- Expulse los medios con IOCTL_STORAGE_EJECT_MEDIA IOCTL. Si el dispositivo no permite la expulsión automática, se puede omitir IOCTL_STORAGE_EJECT_MEDIA y se puede indicar al usuario que elimine el medio.
- Cierre el controlador de volumen obtenido en el primer paso o emita FSCTL_UNLOCK_VOLUME IOCTL. Esto permite que el disco sea utilizado por otros procesos.
La respuesta de Andreas, el artículo de MSKB y mi búsqueda de API Explorer se pueden resumir de la siguiente manera:
-
CreateFile
llamó para abrir el volumen. (Todos los métodos). -
DeviceIoControl
llamó conFSCTL_LOCK_VOLUME
. (Todos los métodos). -
DeviceIoControl
llamó conFSCTL_DISMOUNT_VOLUME
. (Solo para los métodos de Andreas y MSKB. Explorer no llama a esto por algún motivo. Parece que IOCTL afecta a si la unidad está atenuada en Explorer o no. No estoy seguro de por qué Explorer no llama a esto). -
DeviceIoControl
llamó con losIOCTL_STORAGE_MEDIA_REMOVAL
yPREVENT_MEDIA_REMOVAL
establecidos enFALSE
(métodos MSKB y Explorer. Este paso falta en la respuesta de Andreas). -
DeviceIoControl
llamó conIOCTL_STORAGE_EJECT_MEDIA
(artículo de Andreas y MSKB) oIOCTL_DISK_EJECT_MEDIA
(Explorer; tenga en cuenta que esta IOCTL estaba obsoleta y se reemplazó por la IOCTL de ALMACENAMIENTO. No estoy seguro de por qué Explorer todavía usa la anterior).
Para concluir, decidí seguir el procedimiento descrito en el artículo de MSKB, ya que parecía ser el procedimiento más minucioso y completo, respaldado con un artículo de MSKB.
Me gusta usar DeviceIOControl, ya que me da la posibilidad de expulsar cualquier tipo de unidad extraíble (como USB y discos flash, así como las bandejas de CD). Da codez para expulsar correctamente un disco usando DeviceIOControl es (simplemente agregue el manejo de errores adecuado):
bool ejectDisk(TCHAR driveLetter)
{
TCHAR tmp[10];
_stprintf(tmp, _T("////.//%c:"), driveLetter);
HANDLE handle = CreateFile(tmp, GENERIC_READ, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
DWORD bytes = 0;
DeviceIoControl(handle, FSCTL_LOCK_VOLUME, 0, 0, 0, 0, &bytes, 0);
DeviceIoControl(handle, FSCTL_DISMOUNT_VOLUME, 0, 0, 0, 0, &bytes, 0);
DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, 0, 0, 0, 0, &bytes, 0);
CloseHandle(handle);
return true;
}
Para cerrar la bandeja de la unidad, haga lo que se describe aquí, pero en lugar de usar DeviceIoControl con IOCTL_STORAGE_EJECT_MEDIA, debe llamar a DeviceIoControl con IOCTL_STORAGE_LOAD_MEDIA.