Открывать и закрывать лоток CD-ROM можно программными способами. Это может оказаться полезным в случаях, когда системный блок стоит в труднодоступном месте или по каким-либо иным причинам нет возможности управлять им при помощи механической кнопки. Также я читал истории, когда на лоток CD-ROM возлагались полезные функции, например, при выдвижении он замыкал контакты питания и отправлял сервер в перезагрузку, а администратор таким образом удаленно управлял им. Так что программное управление лотком CD-ROM имеет место быть, и наша задача научиться его делать. Чаще всего в разных интернетах описывается способ управления при помощи MCI (Media Control Interface). Кстати, именно этот способ приводится в качестве одного из примеров программ в пакете FASM.
...
; Открыть лоток CD-ROM
invoke mciSendString,cmd_open,0,0,0
invoke mciSendString,cmd_eject,0,0,0
invoke mciSendString,cmd_close,0,0,0
...
; Закрыть лоток CD-ROM
invoke mciSendString,cmd_open,0,0,0
invoke mciSendString,cmd_load,0,0,0
invoke mciSendString,cmd_close,0,0,0
...
cmd_open db 'open cdaudio',0
cmd_eject db 'set cdaudio door open',0
cmd_load db 'set cdaudio door closed',0
cmd_close db 'close cdaudio',0
У данного метода есть недостатки. Главный заключается в том, что при наличии в системе нескольких приводов CD-ROM нет возможности указать, лоток которого из них необходимо выдвигать, всегда открывается первый по счету. Второй существенный недостаток - некоторые антивирусы считают наличие таких функций в программах потенциально опасными. Видимо из-за того, что иногда несанкционированное открытие лотка CD-ROM используется в различных программах-шутках для окошмаривания доверчивых пользователей.
Второй способ заключается в прямом обращении к драйверу дискового устройства с помощью функции управления вводом/выводом, которая называется
DeviceIoControl. Эта функция официально документирована и присутствует на всех системах, начиная с Win9X. В контексте нашей задачи она используется следующим образом:
; Сегмент данных
section '.data' data readable writeable
path db '\\.\E:',0 ; Полное имя CD-ROM
tmp dd ? ; Временная переменная для DeviceIoControl
; Константы в FASM не определены, делаем это сами
IOCTL_DISK_EJECT_MEDIA = 74808h
IOCTL_DISK_LOAD_MEDIA = 7480Ch
; Сегмент кода
section '.code' code readable executable
...
; Открыть лоток CD-ROM
invoke CreateFile,path,GENERIC_READ,FILE_SHARE_READ,\
NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL
mov ebx,eax
invoke DeviceIoControl,ebx,IOCTL_DISK_EJECT_MEDIA,NULL,\
NULL,NULL,NULL,tmp,NULL
invoke CloseHandle,ebx
...
; Закрыть лоток CD-ROM
invoke CreateFile,path,GENERIC_READ,FILE_SHARE_READ,\
NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL
mov ebx,eax
invoke DeviceIoControl,ebx,IOCTL_DISK_LOAD_MEDIA,NULL,\
NULL,NULL,NULL,tmp,NULL
invoke CloseHandle,ebx
...
Константы IOCTL_DISK_EJECT_MEDIA и IOCTL_DISK_LOAD_MEDIA, используемые при вызове функции DeviceIoControl, в FASM изначально не определены, пришлось покопаться в сети и сделать это самостоятельно. Обратите внимание, что в этом случае можно выбирать какой дисковод открыть или закрыть, но путь к нему должен быть прописан в полном формате, например, "\\.\E:" Возможно, что еще потребуется получить список всех дисков, имеющихся в системе, это можно легко сделать при помощи функции
GetLogicalDriveStrings, она возвращает список всех дисков в виде строки:
'A:\', 0, 'C:\', 0, 'D:\', 0, 'E:\', 0, 'F:\', 0, 'G:\', 0, 0
Буквы дисков разделены символов с кодом 00h, строка оканчивается двойным нулем. Чтобы узнать, является ли выбранный диск приводом CD-ROM, проще всего использовать функцию
GetDriveType, она должна вернуть значение DRIVE_CDROM. Вот теперь у нас есть все необходимые инструменты для управления лотком CD-ROM, можете начинать применять их на практике.
В приложении две программы с исходниками, применяющие оба описанных в статье способа управления. Первая использует Media Control Interface для открытия лотка CD-ROM, затем через 5 секунд закрывает его обратно. Вторая использует функцию DeviceIoControl и открывает лотки всех доступных CD-ROM, затем также через 5 секунд закрывает их обратно.