Работа с HDD, CD-ROM, ZIP Работа с HDD, CD-ROM, ZIP
Программное открытие/закрытие лоток CD-ROM |
*
| *
|
| |
Наиболее популярным путем решения этой проблемы является применение mci
// Открыть
mciSendString('Set cdaudio door open wait', nil, 0, handle);
// Закрыть
mciSendString('Set cdaudio door closed wait', nil, 0, handle);
У данного метода есть недостаток - при наличии в системе нескольких CD-ROM
приводов невозможно указать, лоток какого из них необходимо выдвигать.
Для систем, основанных на платформе W9x или NT (NT, W2K, W3K, XP) существует красивое
(и главное - документированное) решение:
var
hCDDevice : THandle;
lpBytesReturned: DWORD;
DriveLetter : char;
begin
DriveLetter := 'G';
hCDDevice := CreateFile(PChar('\\.\'+DriveLetter+':'),
GENERIC_READ,
FILE_SHARE_READ or FILE_SHARE_WRITE,
nil,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0);
if hCDDevice <> INVALID_HANDLE_VALUE then begin
DeviceIoControl(hCDDevice, IOCTL_DISK_EJECT_MEDIA , nil, 0, nil, 0, lpBytesReturned, nil);
CloseHandle(hCDDevice);
end;
end;
Константа IOCTL_DISK_EJECT_MEDIA не декларирована в Delphi и для реализации
данного примера рекомендуется скачать модуль
winIoctl, портированный в Delphi из SDK или объявить
константу IOCTL_DISK_EJECT_MEDIA = $074808.
Для закрытия лотка CD-ROM в данном примере при вызове DeviceIoControl необходимо
передать параметр IOCTL_DISK_LOAD_MEDIA (значение - $07480C)
Как узнать, вставлена ли дискета в дисковод (или диск в CDROM) и каковы его параметры |
*
| *
|
| |
Определить готовность устройства и наличие в нем носителя проще всего при
помощи функции API GetDiskFreeSpace. Данная функция при вызове должна получать
имя диска в формате "диск:\" в виде строки PCHAR. Если устройство готово к работе
и в нем есть носитель, то возвращается TRUE, при ошибках или отсутствии носителя -
FALSE. По этому признаку можно судить о наличии дискеты в дисководе. Кроме того,
при успешном выполнении функция заполняет последние четыре параметра информацией
о диске:
SectorsPerCluster - число секторов на кластер
BytesPerSector - число байт на сектор
NumberOfFreeClusters - число свободных кластеров
TotalNumberOfClusters - общее число кластеров на диске
Function DiskInDrive(ADriveLetter : Char) : Boolean;
var
SectorsPerCluster,
BytesPerSector,
NumberOfFreeClusters,
TotalNumberOfClusters : Cardinal;
begin
Result := GetDiskFreeSpace(PChar(ADriveLetter+':\'),
SectorsPerCluster,
BytesPerSector,
NumberOfFreeClusters,
TotalNumberOfClusters);
end;
В FAQ по Delphi можно встретить другой вариант реализации:
Result := false;
try
ChDir('a:\');
Result := true;
except end;
Такой вариант (известно множество его реализаций - главное, что принцип основан
на применении ChDir) несколько некорректен, т.к. приводит к смене текущего
каталога, что не всегда желательно. Решить эту проблему позволяет запоминание
текущего каталога при помощи функции GetDir и его восстановление после проверки
при помощи ChDir.
Известен еще один способ - проверка при помощи FindFirst:
var
SR : TSearchRec;
Res : integer;
OldErrMode : integer;
begin
// Запоминаем текущий режим обработки ошибок и устанавливаем SEM_FAILCRITICALERRORS
// Это необходимо для подавления появления окна с сообщение о том, что устройство не готово
OldErrMode = SetErrorMode(SEM_FAILCRITICALERRORS);
try
Res := FindFirst('a:\*.*', faAnyfile, SR);
FindClose(SR);
finally
SetErrorMode(OldErrMode)
end;
end;
Определение серийного номера тома винчестера |
*
| *
|
| |
Привожу типовой код определения серийного номера - это непосредственно фрагмент одного из классов
мой библиотеки для защиты программ от нелегального копирования
function TProtect.GetHDDSerial(ADisk : char): dword;
var
SerialNum : dword;
a, b : dword;
VolumeName : array [0..255] of char;
begin
Result := 0;
if GetVolumeInformation(PChar(ADisk + ':\'), VolumeName, SizeOf(VolumeName),
@SerialNum, a, b, nil, 0) then
Result := SerialNum;
end;
На заметку:
1. Следует помнить, что замечательная утилита FILEMON регистрирует запрос
серийного номера. Поэтому не следует надеяться на то, что хакер не заметит
определения серийного номера. Поэтому при построении защиты я бы рекомендовал
определить его пару раз просто так, уж очень это заметно ...
2. Это номер тома, а не жесткого диска. Я часто встречаю подобную
путаницу даже в проверенных серьезных источниках. Поэтому то моя функция и
получает в качестве параметра букву того тома, для которого следует получить
номер.
Определение метки тома и типа файловой системы на указанном диске |
*
| *
|
| |
Для определения метки тома и типа файловой системы на диске применяется
функция API GetVolumeInformation:
function GetHDDFileSystem(ADisk : char): String;
var
SerialNum : dword;
VolumeName, FSName : array [0..255] of char;
MaximumFNameLength,
FileSystemFlags : dword;
begin
Result := '';
if GetVolumeInformation(PChar(ADisk + ':\'),
VolumeName, SizeOf(VolumeName),
@SerialNum,
MaximumFNameLength,
FileSystemFlags,
FSName, SizeOf(FSName)) then
Result := FSName;
end;
На заметку:
Кроме названия файловой системы данная функция возвращает серийный номер диска
в переменной SerialNum, имя тома в переменной VolumeName, максимальную длину
имени файла MaximumFNameLength и флаги файловой системы FileSystemFlags.
Имя файловой системы представляет собой строчку с одним из вариантов:
для FAT32. При попытке вызова данной функции для CDROM возвращается пустая строка.
Флаги кодируют информацию об устройстве
FS_CASE_IS_PRESERVED | Если флаг установлен, то файловая система сохраняет регистр имен файлов |
FS_CASE_SENSITIVE | Если флаг установлен, то файловая система поддерживает регистро-зависимые имена |
FS_UNICODE_STORED_ON_DISK | Если флаг установлен, то файловая система поддерживает Unicode в именах файлов. |
FS_PERSISTENT_ACLS | Если данный флаг установлен, то файловая система поддерживает "enforces ACLs" - списки
контроля доступа. Например, NTFS его поддерживает, а FAT - нет. |
FS_FILE_COMPRESSION | Файловая система поддерживает сжатие на уровне файлов |
FS_VOL_IS_COMPRESSED | Признак того, что данный диск сжат (например, DoubleSpace диск). |
Как определить тип диска |
*
| *
|
| |
Для определения типа диска применяется функция API GetDriveType, возвращающая флаги
информации об устройстве. Формат вызова:
GetDriveType(lpRootPathName : PChar) : Word;
Возврат - набор флагов
0 | Устройство не определено |
1 | Root directory не существует |
DRIVE_REMOVABLE | Признак того, что в данном устройстве диск может быть извлечен
(например, у дисковода или CD-ROM). |
DRIVE_FIXED | Признак того, что в данном устройстве диск не может быть
извлечен (например, HDD). |
DRIVE_REMOTE | Удаленное (сетевое) устройство. |
DRIVE_CDROM | Устройство является приводом CD-ROM. |
DRIVE_RAMDISK | Устройство является RAM диском. |
Как получить информацию о доступных в системе логических дисках |
*
| W9x
|
| |
Для получения информации о доступных в системе логических дисках применяется
функция API GetLogicalDrives:DWORD;
Возврат - битовая маска. Бит 0 соответствует устройству A:, 1-B: и т.п.
Если при вызове функции возникает ошибка, то она возвращает 0.
Кроме GetLogicalDrives существует аналогичная функция GetLogicalDriveStrings,
вызываемая с двумя параметрами:
GetLogicalDriveStrings(размер буфера, указатель на буфер):DWORD;
Буфер заполняется информацией о доступных дисках в формате
c:\#0d:\#0#0
т.е. информация о дисках разделена символом NULL (#0) и завершается нулем.
При успешно вызове функция возвращает длину информации, которая была помещена
в буфер, при ошибке - 0.
Данная функция не требует готовности устройств и наличия дисков в дисководах,
ZIP и CD-ROM.
Пример - заполнение списка данными о доступных дисках
function TForm1.CreateDrivesList(AList: TStrings): boolean;
var
Bufer : array[0..1024] of char; // Буфер
RealLen, i : integer; // Результирующая длина
S : string; // Времменная строка
begin
AList.Clear;
// Составление списка устройств
RealLen := GetLogicalDriveStrings(SizeOf(Bufer),Bufer);
i := 0; S := '';
// Цикл анализа буфера (последний символ не обрабатывается, т.к. он всегда #0)
while i < RealLen do begin
if Bufer[i] <> #0 then begin
S := S + Bufer[i];
inc(i);
end else begin
inc(i); // Пропуск разделяющего #0
AList.Add(S);
S := '';
end;
end;
Result := AList.Count > 0;
end;
// Пример вызова
procedure TForm1.Button1Click(Sender: TObject);
begin
CreateDrivesList(ListBox1.Items);
end;
Чтение/запись метки тома через API |
*
| *
|
| |
Для работы с меткой тома в API предусмотрено две функции:
- SetVolumeLabel(PCHAR(том), PCHAR(новая метка)) - присвоение метки тома,
том определяется строкой формата "C:\"
- GetVolumeInformation - чтение метки тома.
© Зайцев Олег, "Программирование на Delphi - обмен опытом" 1999-2004. При использовании любых материалов данного сайта
необходимо указывать источник информации. Дата обновления: 22.11.2004. Сайт размещен на хостинге AGAVA - Хостинг от AGAVA.ru