Программирование на Delphi - обмен опытом / Работа с HDD, CD-ROM, ZIP

© Зайцев Олег 1998-2004
Лучшая портативная техника. Плееры Камеры Телефоны Компьютеры
Покупателям, пришедшим на www.porta.ru по этой ссылке - дополнительная скидка 1%
Железо | Система | WEB | Компоненты | Графика | Ссылки | Мультимедиа | Сети | Прочее | Реестр | Литература

Статистика

Работа с HDD, CD-ROM, ZIP

Рекомендую:
Главная страница \ Железо \ Работа с HDD, CD-ROM, ZIP

  • Работа с 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Устройство не определено
    1Root 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 предусмотрено две функции:


    © Зайцев Олег, "Программирование на Delphi - обмен опытом" 1999-2004. При использовании любых материалов данного сайта необходимо указывать источник информации. Дата обновления: 22.11.2004. Сайт размещен на хостинге AGAVA - Хостинг от AGAVA.ru