Валерий Борисок - Delphi. Трюки и эффекты
• ссылка на переменную типа Cardinal для сохранения в ней набора битовых флагов с некоторыми параметрами файловой системы;
• буфер для названия файловой системы (и его длина).
Как вы могли заметить, результатом работы приведенной в листинге 4.4 функции GetDrivelnf ormation является заполнение структуры (записи) Drivelnf о. Определение этой структуры (а также вложенной в нее структуры, хранящей некоторые извлеченные из битовой маски fsOptions флаги) приводится в листинге 4.5.
...Листинг 4.5.
Определение записей для хранения информации о диске
Type
//Запись некоторых параметров о файловой системе
FSOptions = record
CaseSensitive: Boolean; //При уравнении путей
//учитывает регистр
SupportCompression: Boolean; //Файловая система
//поддерживает сжатие
IsCompressed: Boolean; //Диск сжат
end;
//Запись, содержащая информацию о диске
DriveInfo = record
DriveLabel: String; //Метка диска
FileSystemName: String; //Файловая система диска
FileSystemOptions: FSOptions; //Параметры файловой системы
SerialNumber: DWORD; //Серийный номер тома
MaxFileNameLen: Cardinal; //Максимальная длина имени
//файла
end;
Напоследок рассмотрим еще одну полезную возможность – определение типа носителя диска при помощи API-функции GetDriveType. Она принимает единственный параметр, задающий корневую папку диска (например, С: , причем обратный слэш на конце обязателен). Функция GetDriveType возвращает целочисленное значение, идентифицирующее тип диска. Вариант получения текстового описания типов дисков с использованием этой API-функции приведен в листинге 4.6.
...Листинг 4.6.
Определение типа носителя диска
function GetDriveTypeName(root: String): String;
begin
case GetDriveType(PAnsiChar(root)) of
DRIVE_UNKNOWN: GetDriveTypeName := 'Не определен
DRIVE_REMOVABLE: GetDriveTypeName := 'Сменный
DRIVE_FIXED: GetDriveTypeName := 'Фиксированный
DRIVE_REMOTE: GetDriveTypeName := 'Удаленный (сетевой)
DRIVE_CDROM: GetDriveTypeName := 'Компакт-диск
DRIVE_RAMDISK: GetDriveTypeName := 'RAM-диск
else
GetDriveTypeName := '' //Возвращается в случае ошибки
end;
end;
Изменение метки диска
Как вы думаете, сложно ли изменить метку диска? Совсем нет: вся сложность состоит в отыскании нужной функции. В данном случае можно применить API-функцию SetVolumeLabel (листинг 4.7).
...Листинг 4.7.
Изменение метки диска
function SetDriveLabel(root, newLabel: String): Boolean;
begin
SetDriveLabel :=
SetVolumeLabel(PAnsiChar(root), PAnsiChar(newLabel)) <> False;
end;
В листинге 4.7 приведена функция-оболочка для API-функции изменения метки диска, избавляющая нас от необходимости преобразования типов и интерпретации значения, возвращаемого API-функцией.
Программа просмотра свойств дисков
В завершение темы работы с дисками рассмотрим еще небольшой пример, обобщающий сказанное выше. Для этого создадим небольшое приложение, выводящее информацию о любом из дисков компьютера. Приложение должно использовать возможности всех рассмотренных выше функций.
Окно этого приложения приведено на рис. 4.1.
Рис. 4.1. Окно с информацией о дисках
Работа формы, приведенной на рис. 4.1, организована предельно просто. Сначала при создании формы получаем список дисков (а также выделяем первый диск и загружаем информацию о нем) (листинг 4.8).
...Листинг 4.8.
Составление списка дисков
procedure TForm1.FormCreate(Sender: TObject);
begin
//Загрузка букв дисков
if GetDriveLetters(cboDrives.Items) > 0 then
begin
//Выделим первый диск
cboDrives.ItemIndex := 0;
cboDrivesSelect(self);
end
else
Button1.Enabled := False;
end;
Загрузка информации о дисках происходит при выборе буквы диска в списке (листинг 4.9).
...Листинг 4.9. Загрузка информации о выбранном диске
procedure TForm1.cboDrivesSelect(Sender: TObject);
var info: DriveInfo;
root: String;
fullSize, freeSize: Int64;
begin
root := cboDrives.Items[cboDrives.ItemIndex];
//Загружаем информацию о выбранном диске
GetDriveInformation(root, info);
//Общая информация о диске и файловой системе
txtLabel.Text := info.DriveLabel;
txtDriveType.Text := GetDriveTypeName(root);
txtFSName.Text := info.FileSystemName;
txtSN.Text := IntToHex(Int64(info.SerialNumber), 8);
txtMaxFileName.Text := IntToStr(Integer(info.MaxFileNameLen));
//Флажки некоторых свойств файловой системы
chkCaseSensitive.Checked := info.FileSystemOptions.CaseSensitive;
chkCompression.Checked := info.FileSystemOptions.SupportCompression;
chkCompressed.Checked := info.FileSystemOptions.IsCompressed;
//Размер диска
fullSize := GetDriveSize(root);
if fullSize <> –1 then
freeSize := GetDriveFreeSpace(root)
else
begin //Ошибка при обращении к диску
fullSize := 0;
freeSize := 0;
end;
//..формирование диаграммы
driveSize.Series[0].Clear;
driveSize.Series[0].Add( freeSize, 'Свободно');
driveSize.Series[0].Add( fullSize – freeSize, 'Занято')
end;
При нажатии кнопки Изменить производится попытка присвоить выбранному в списке диску метку, введенную в соответствующее текстовое поле (txtLabel) (листинг 4.10).
...Листинг 4.10.
Задание новой метки диска
procedure TForm1.Button1Click(Sender: TObject);
begin
//Изменение метки диска
if not SetDriveLabel(cboDrives.Items[cboDrives.ItemIndex],
txtLabel.Text)
then
MessageBox(self.Handle, 'Не удалось поменять метку диска',
'Ошибка', MB_ICONEXCLAMATION)
else
//Перечитаем информацию о диске
cboDrivesSelect(self);
end;
Табличное или иное описание свойств элементов управления не приводится, так как имена элементов управления соответствуют виду информации, помещаемой в них. Только следует уточнить, что в элементе управления TChart создан один ряд типа Pie (круговая диаграмма). У этого ряда отключено отображение подписей к диаграмме, чтобы не дублировать данные, приведенные в легенде.
4.2. Каталоги и пути
В этом разделе описываются некоторые полезные примеры, позволяющие узнавать расположение важных каталогов операционной системы Windows. Здесь также рассматриваются вопросы преобразования путей и приводятся некоторые алгоритмы обхода каталогов, применяемые для поиска.
Прежде чем рассматривать решения конкретных задач, следует уточнить, что за магическое число, а точнее, целочисленная константа используется в некоторых примерах, приведенных далее. Речь идет о константе МАХРАТН, равной 260. Она используется явно или неявно (функциями API) в качестве максимально возможной длины пути. Здесь налицо небольшой парадокс: хотя такая файловая система как FAT32, и реализована так, что может поддерживать неограниченную вложенность каталогов, в реальности не получится создать даже два вложенных каталога с именем длиной 255 символов.
...Примечание
При доскональной проверке вышесказанного выяснилось, что не получится создать даже один каталоге именем длиной 255 символов в корневой папке диска (например, С: ). Каталог может иметь имя длиной максимум 244 символа. С учетом длины имени корневой папки (получается 247) можно предположить, что в таком случае система резервирует оставшиеся 13 символов, чтобы в папке можно было сохранять файлы с именем в формате 8.3 (MS-DOS).
Системные папки WINDOWS и system
Приходилось ли вам хоть раз писать приложения, работоспособность которых зависела от расположения системных папок Windows? Если да, то вы наверняка хорошо знаете, как неустойчиво предположение о том, что папка WINDOWS всегда C:WIND0WS, a system всегда C:WINDOWSsystem. Ведь при установке операционной системы ничто не мешает поместить ее, например, на диск Е:, а папку для Windows назвать Linux. Кроме того, системная папка Windows на платформе NT имеет имя system32, и кто знает, какое имя она будет иметь в следующей версии Windows. В таких и многих других случаях выручат API-функции: GetWindowsDirectory и GetSystemDirectory. Они обе принимают в качестве параметров строковый буфер и его длину и возвращают количество символов, записанных в переданный буфер, или 0 в случае ошибки.
Для этих функций удобно реализовывать функции-оболочки, работающие со стандартными для Delphi строками, что, собственно, и сделано при написании этой главы (все реализованные функции вы можете найти в модуле PathFunctions, расположенном на диске, прилагаемом к книге, в папке с названием подраздела). Итак, функция определения папки Windows приведена в листинге 4.11.
...Листинг 4.11.
Определение папки WINDOWS
function GetWinDir(): String;
var
buffer: String;
len: UINT;
begin
SetLength(buffer, MAX_PATH + 1);
len := GetWindowsDirectory(PAnsiChar(buffer), MAX_PATH);
SetLength(buffer, len);
GetWinDir := buffer;
end;
По аналогии реализуется функция определения расположения системной папки, только вместо GetWindowsDirectory вызывается фyнкцияGetSystemDirectory.
Имена для временных файлов
Для централизованного хранения временных данных, необходимых при работе приложений, в Windows предусмотрена специальная папка Temp. Ее расположение может варьироваться. Причем в многопользовательских версиях Windows (NT, 2000, ХР) местоположение папки для временных файлов может быть различным для различных пользователей. Итак, расположение папки Temp поможет определить API-функция GetTempPath. Она принимает следующие параметры: строковый буфер и длину этого буфера. Возвращает количество символов, записанных в переданную строку, или 0, если возникла ошибка. Функция-оболочка, скрывающая работу со строковым буфером и преобразование типов, реализуется аналогично двум ранее рассмотренным функциям (листинг 4.12).